rebly-sections 1.3.1 → 1.4.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/assets/data/animations.csv +29 -0
- package/assets/data/component-library/features-grid.liquid +159 -25
- package/assets/data/component-library/hero-banner.liquid +166 -53
- package/assets/data/component-library/image-gallery.liquid +160 -32
- package/assets/data/component-library/pricing-table.liquid +224 -36
- package/assets/data/component-library/testimonials-slider.liquid +216 -46
- package/assets/data/design-tokens.csv +42 -0
- package/assets/scripts/core.py +7 -1
- package/assets/scripts/quality-gate-design-checks.py +101 -0
- package/assets/scripts/quality-gate.py +31 -0
- package/assets/scripts/section-generator.py +20 -31
- package/assets/scripts/ux-bridge.py +197 -0
- package/assets/templates/generation-prompt.md +5 -1
- package/package.json +1 -1
|
@@ -1,85 +1,253 @@
|
|
|
1
|
-
{%- comment -%} rebly-sections: Testimonials Slider | Category: social-proof | OS2.0 {%- endcomment -%}
|
|
1
|
+
{%- comment -%} rebly-sections: Testimonials Slider | Category: social-proof | OS2.0 | CSS scroll-snap carousel {%- endcomment -%}
|
|
2
|
+
{%- assign font = section.settings.heading_font -%}
|
|
3
|
+
{%- assign heading_tag = section.settings.heading_tag -%}
|
|
4
|
+
{%- assign block_count = section.blocks | where: 'type', 'testimonial' | size -%}
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
{{ font | font_face: font_display: 'swap' }}
|
|
7
|
+
|
|
8
|
+
<section id="section-{{ section.id }}" class="testimonials-slider color-{{ section.settings.color_scheme }}">
|
|
9
|
+
<div class="testimonials-slider__container" style="
|
|
10
|
+
--pt: {{ section.settings.padding_top }}px;
|
|
11
|
+
--pb: {{ section.settings.padding_bottom }}px;
|
|
12
|
+
--heading-size: {{ section.settings.heading_font_size }}px;
|
|
13
|
+
--heading-font: {{ font.family }}, {{ font.fallback_families }};
|
|
14
|
+
--heading-weight: {{ font.weight }};
|
|
15
|
+
--slide-count: {{ block_count }};
|
|
16
|
+
">
|
|
5
17
|
|
|
6
18
|
{%- if section.settings.heading != blank -%}
|
|
7
|
-
<
|
|
19
|
+
<{{ heading_tag }} class="testimonials-slider__heading">{{ section.settings.heading | escape }}</{{ heading_tag }}>
|
|
8
20
|
{%- endif -%}
|
|
9
21
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
{%- comment -%} CSS scroll-snap carousel — no JS library, GPU-only scroll {%- endcomment -%}
|
|
23
|
+
<div class="testimonials-slider__viewport" id="ts-viewport-{{ section.id }}">
|
|
24
|
+
<div class="testimonials-slider__track">
|
|
25
|
+
{%- for block in section.blocks -%}
|
|
26
|
+
{%- if block.type == 'testimonial' -%}
|
|
27
|
+
<article class="testimonials-slider__slide" {{ block.shopify_attributes }} id="ts-slide-{{ section.id }}-{{ forloop.index }}">
|
|
28
|
+
{%- comment -%} Decorative oversized quote mark {%- endcomment -%}
|
|
29
|
+
<span class="testimonials-slider__quote-mark" aria-hidden="true">“</span>
|
|
30
|
+
|
|
31
|
+
{%- if block.settings.rating > 0 -%}
|
|
32
|
+
<div class="testimonials-slider__stars" aria-label="{{ block.settings.rating }} out of 5 stars">
|
|
33
|
+
{%- for i in (1..5) -%}
|
|
34
|
+
<span class="testimonials-slider__star{% if i <= block.settings.rating %} testimonials-slider__star--filled{% endif %}" aria-hidden="true">★</span>
|
|
35
|
+
{%- endfor -%}
|
|
36
|
+
</div>
|
|
17
37
|
{%- endif -%}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
</div>
|
|
38
|
+
|
|
39
|
+
<blockquote class="testimonials-slider__blockquote">
|
|
40
|
+
{%- if block.settings.quote != blank -%}
|
|
41
|
+
<p class="testimonials-slider__text">{{ block.settings.quote | escape }}</p>
|
|
23
42
|
{%- endif -%}
|
|
24
|
-
<
|
|
25
|
-
{%- if block.settings.
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
43
|
+
<footer class="testimonials-slider__author">
|
|
44
|
+
{%- if block.settings.avatar != blank -%}
|
|
45
|
+
<div class="testimonials-slider__avatar">
|
|
46
|
+
<img
|
|
47
|
+
src="{{ block.settings.avatar | image_url: width: 96 }}"
|
|
48
|
+
srcset="{{ block.settings.avatar | image_url: width: 96 }} 1x, {{ block.settings.avatar | image_url: width: 192 }} 2x"
|
|
49
|
+
loading="lazy"
|
|
50
|
+
alt="{{ block.settings.author | escape }}"
|
|
51
|
+
width="48" height="48"
|
|
52
|
+
>
|
|
53
|
+
</div>
|
|
54
|
+
{%- else -%}
|
|
55
|
+
<div class="testimonials-slider__avatar testimonials-slider__avatar--initials" aria-hidden="true">
|
|
56
|
+
{{ block.settings.author | slice: 0 | upcase }}
|
|
57
|
+
</div>
|
|
30
58
|
{%- endif -%}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
<div class="testimonials-slider__meta">
|
|
60
|
+
{%- if block.settings.author != blank -%}
|
|
61
|
+
<cite class="testimonials-slider__name">{{ block.settings.author | escape }}</cite>
|
|
62
|
+
{%- endif -%}
|
|
63
|
+
{%- if block.settings.role != blank -%}
|
|
64
|
+
<span class="testimonials-slider__role">{{ block.settings.role | escape }}</span>
|
|
65
|
+
{%- endif -%}
|
|
66
|
+
</div>
|
|
67
|
+
</footer>
|
|
68
|
+
</blockquote>
|
|
69
|
+
</article>
|
|
70
|
+
{%- endif -%}
|
|
71
|
+
{%- endfor -%}
|
|
72
|
+
</div>
|
|
37
73
|
</div>
|
|
38
74
|
|
|
75
|
+
{%- comment -%} Navigation dots — JS-driven active state, CSS-only styling {%- endcomment -%}
|
|
76
|
+
{%- if block_count > 1 -%}
|
|
77
|
+
<nav class="testimonials-slider__dots" aria-label="Testimonial navigation">
|
|
78
|
+
{%- for block in section.blocks -%}
|
|
79
|
+
{%- if block.type == 'testimonial' -%}
|
|
80
|
+
<button
|
|
81
|
+
class="testimonials-slider__dot{% if forloop.first %} is-active{% endif %}"
|
|
82
|
+
data-index="{{ forloop.index0 }}"
|
|
83
|
+
aria-label="Go to testimonial {{ forloop.index }}"
|
|
84
|
+
></button>
|
|
85
|
+
{%- endif -%}
|
|
86
|
+
{%- endfor -%}
|
|
87
|
+
</nav>
|
|
88
|
+
{%- endif -%}
|
|
89
|
+
|
|
39
90
|
</div>
|
|
40
91
|
</section>
|
|
41
92
|
|
|
42
93
|
<style>
|
|
43
|
-
|
|
44
|
-
#section-{{ section.id }} .testimonials-slider__container {
|
|
45
|
-
|
|
94
|
+
/* ── Layout ── */
|
|
95
|
+
#section-{{ section.id }} .testimonials-slider__container {
|
|
96
|
+
max-width: 1100px; margin: 0 auto;
|
|
97
|
+
padding: var(--pt, 80px) 2rem var(--pb, 80px);
|
|
98
|
+
}
|
|
99
|
+
#section-{{ section.id }} .testimonials-slider__heading {
|
|
100
|
+
font-family: var(--heading-font); font-weight: var(--heading-weight);
|
|
101
|
+
font-size: clamp(1.75rem, 3vw, var(--heading-size, 2.5rem));
|
|
102
|
+
text-align: center; margin: 0 0 3rem; color: rgb(var(--color-foreground));
|
|
103
|
+
}
|
|
104
|
+
/* ── Scroll-snap viewport ── */
|
|
105
|
+
#section-{{ section.id }} .testimonials-slider__viewport {
|
|
106
|
+
overflow: hidden; /* JS scrolls underlying track */
|
|
107
|
+
}
|
|
46
108
|
#section-{{ section.id }} .testimonials-slider__track {
|
|
47
|
-
display: flex; gap: 1.5rem;
|
|
48
|
-
scroll-snap
|
|
49
|
-
|
|
109
|
+
display: flex; gap: 1.5rem;
|
|
110
|
+
/* scroll-snap on the track so CSS-only fallback works too */
|
|
111
|
+
overflow-x: auto; scroll-snap-type: x mandatory;
|
|
112
|
+
-webkit-overflow-scrolling: touch; scrollbar-width: none;
|
|
113
|
+
scroll-behavior: smooth;
|
|
50
114
|
}
|
|
51
115
|
#section-{{ section.id }} .testimonials-slider__track::-webkit-scrollbar { display: none; }
|
|
116
|
+
/* ── Slide cards ── */
|
|
52
117
|
#section-{{ section.id }} .testimonials-slider__slide {
|
|
53
118
|
flex: 0 0 calc(33.333% - 1rem); min-width: 280px;
|
|
54
|
-
scroll-snap-align: start;
|
|
55
|
-
|
|
119
|
+
scroll-snap-align: start;
|
|
120
|
+
background: rgb(var(--color-background));
|
|
121
|
+
border: 1px solid rgba(var(--color-foreground), 0.1);
|
|
122
|
+
border-radius: 16px; padding: 2.25rem; position: relative;
|
|
123
|
+
overflow: hidden;
|
|
124
|
+
transition: transform 0.35s cubic-bezier(0.22,1,0.36,1), box-shadow 0.35s ease;
|
|
125
|
+
will-change: transform;
|
|
126
|
+
}
|
|
127
|
+
#section-{{ section.id }} .testimonials-slider__slide:hover {
|
|
128
|
+
transform: translateY(-6px);
|
|
129
|
+
box-shadow: 0 20px 60px rgba(var(--color-foreground), 0.1);
|
|
130
|
+
}
|
|
131
|
+
/* ── Decorative quote mark ── */
|
|
132
|
+
#section-{{ section.id }} .testimonials-slider__quote-mark {
|
|
133
|
+
position: absolute; top: -0.25rem; right: 1.25rem;
|
|
134
|
+
font-size: 6rem; line-height: 1; opacity: 0.08;
|
|
135
|
+
color: rgb(var(--color-foreground)); pointer-events: none;
|
|
136
|
+
font-family: Georgia, serif;
|
|
137
|
+
}
|
|
138
|
+
/* ── Stars ── */
|
|
139
|
+
#section-{{ section.id }} .testimonials-slider__stars { margin-bottom: 1rem; }
|
|
140
|
+
#section-{{ section.id }} .testimonials-slider__star { font-size: 1rem; opacity: 0.25; color: rgb(var(--color-foreground)); }
|
|
141
|
+
#section-{{ section.id }} .testimonials-slider__star--filled { opacity: 1; color: #f5a623; }
|
|
142
|
+
/* ── Quote text ── */
|
|
143
|
+
#section-{{ section.id }} .testimonials-slider__blockquote { margin: 0; }
|
|
144
|
+
#section-{{ section.id }} .testimonials-slider__text {
|
|
145
|
+
font-size: 1rem; line-height: 1.75; margin: 0 0 1.75rem;
|
|
146
|
+
font-style: italic; color: rgb(var(--color-foreground)); opacity: 0.85;
|
|
147
|
+
}
|
|
148
|
+
/* ── Author ── */
|
|
149
|
+
#section-{{ section.id }} .testimonials-slider__author { display: flex; align-items: center; gap: 0.875rem; }
|
|
150
|
+
#section-{{ section.id }} .testimonials-slider__avatar {
|
|
151
|
+
width: 48px; height: 48px; border-radius: 50%; overflow: hidden;
|
|
152
|
+
flex-shrink: 0; background: rgba(var(--color-button), 0.15);
|
|
56
153
|
}
|
|
57
|
-
#section-{{ section.id }} .testimonials-slider__text { font-size: 1.05rem; line-height: 1.7; margin: 0 0 1.5rem; font-style: italic; color: inherit; }
|
|
58
|
-
#section-{{ section.id }} .testimonials-slider__author { display: flex; align-items: center; gap: 0.75rem; }
|
|
59
|
-
#section-{{ section.id }} .testimonials-slider__avatar { width: 48px; height: 48px; border-radius: 50%; overflow: hidden; flex-shrink: 0; }
|
|
60
154
|
#section-{{ section.id }} .testimonials-slider__avatar img { width: 100%; height: 100%; object-fit: cover; }
|
|
61
|
-
#section-{{ section.id }} .testimonials-
|
|
62
|
-
|
|
63
|
-
|
|
155
|
+
#section-{{ section.id }} .testimonials-slider__avatar--initials {
|
|
156
|
+
display: grid; place-items: center;
|
|
157
|
+
font-weight: 700; font-size: 1.1rem; color: rgb(var(--color-button));
|
|
158
|
+
}
|
|
159
|
+
#section-{{ section.id }} .testimonials-slider__meta { display: flex; flex-direction: column; gap: 0.15rem; }
|
|
160
|
+
#section-{{ section.id }} .testimonials-slider__name {
|
|
161
|
+
font-style: normal; font-weight: 700; font-size: 0.9375rem;
|
|
162
|
+
color: rgb(var(--color-foreground));
|
|
163
|
+
}
|
|
164
|
+
#section-{{ section.id }} .testimonials-slider__role { font-size: 0.8125rem; opacity: 0.6; color: rgb(var(--color-foreground)); }
|
|
165
|
+
/* ── Navigation dots ── */
|
|
166
|
+
#section-{{ section.id }} .testimonials-slider__dots {
|
|
167
|
+
display: flex; justify-content: center; gap: 0.5rem; margin-top: 2rem;
|
|
168
|
+
}
|
|
169
|
+
#section-{{ section.id }} .testimonials-slider__dot {
|
|
170
|
+
width: 8px; height: 8px; border-radius: 50%; border: none; cursor: pointer;
|
|
171
|
+
background: rgba(var(--color-foreground), 0.2);
|
|
172
|
+
transition: background 0.3s ease, transform 0.3s ease;
|
|
173
|
+
padding: 0;
|
|
174
|
+
}
|
|
175
|
+
#section-{{ section.id }} .testimonials-slider__dot.is-active {
|
|
176
|
+
background: rgb(var(--color-button)); transform: scale(1.4);
|
|
177
|
+
}
|
|
178
|
+
/* ── Reduced motion ── */
|
|
179
|
+
@media (prefers-reduced-motion: reduce) {
|
|
180
|
+
#section-{{ section.id }} .testimonials-slider__track { scroll-behavior: auto; }
|
|
181
|
+
#section-{{ section.id }} .testimonials-slider__slide { transition: none; }
|
|
182
|
+
#section-{{ section.id }} .testimonials-slider__dot { transition: none; }
|
|
183
|
+
}
|
|
184
|
+
/* ── Responsive ── */
|
|
185
|
+
@media (max-width: 989px) {
|
|
186
|
+
#section-{{ section.id }} .testimonials-slider__slide { flex: 0 0 calc(50% - 0.75rem); }
|
|
187
|
+
}
|
|
188
|
+
@media (max-width: 749px) {
|
|
189
|
+
#section-{{ section.id }} .testimonials-slider__slide { flex: 0 0 88%; }
|
|
190
|
+
#section-{{ section.id }} .testimonials-slider__container { padding-left: 1.25rem; padding-right: 1.25rem; }
|
|
191
|
+
}
|
|
64
192
|
</style>
|
|
65
193
|
|
|
194
|
+
<script>
|
|
195
|
+
/* Dot-nav + keyboard navigation for scroll-snap carousel */
|
|
196
|
+
(function() {
|
|
197
|
+
var viewport = document.getElementById('ts-viewport-{{ section.id }}');
|
|
198
|
+
var track = viewport && viewport.querySelector('.testimonials-slider__track');
|
|
199
|
+
var dots = document.querySelectorAll('#section-{{ section.id }} .testimonials-slider__dot');
|
|
200
|
+
var slides = document.querySelectorAll('#section-{{ section.id }} .testimonials-slider__slide');
|
|
201
|
+
if (!track || !slides.length) return;
|
|
202
|
+
|
|
203
|
+
function scrollToSlide(index) {
|
|
204
|
+
var slide = slides[index];
|
|
205
|
+
if (!slide) return;
|
|
206
|
+
track.scrollTo({ left: slide.offsetLeft, behavior: window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth' });
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
dots.forEach(function(dot) {
|
|
210
|
+
dot.addEventListener('click', function() { scrollToSlide(parseInt(this.dataset.index, 10)); });
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
/* Update active dot on scroll */
|
|
214
|
+
var io = new IntersectionObserver(function(entries) {
|
|
215
|
+
entries.forEach(function(entry) {
|
|
216
|
+
if (!entry.isIntersecting) return;
|
|
217
|
+
var idx = Array.prototype.indexOf.call(slides, entry.target);
|
|
218
|
+
dots.forEach(function(d, i) { d.classList.toggle('is-active', i === idx); });
|
|
219
|
+
});
|
|
220
|
+
}, { root: track, threshold: 0.6 });
|
|
221
|
+
slides.forEach(function(s) { io.observe(s); });
|
|
222
|
+
})();
|
|
223
|
+
</script>
|
|
224
|
+
|
|
66
225
|
{% schema %}
|
|
67
226
|
{
|
|
68
227
|
"name": "Testimonials Slider",
|
|
69
228
|
"tag": "section",
|
|
70
229
|
"class": "section-testimonials-slider",
|
|
71
230
|
"settings": [
|
|
231
|
+
{ "type": "color_scheme", "id": "color_scheme", "label": "Color Scheme", "default": "scheme-1" },
|
|
232
|
+
{ "type": "font_picker", "id": "heading_font", "label": "Heading Font", "default": "helvetica_n4" },
|
|
233
|
+
{ "type": "range", "id": "heading_font_size", "label": "Heading Size (px)", "min": 20, "max": 56, "step": 2, "default": 40 },
|
|
234
|
+
{ "type": "select", "id": "heading_tag", "label": "Heading Tag", "options": [
|
|
235
|
+
{ "value": "h1", "label": "H1" }, { "value": "h2", "label": "H2" },
|
|
236
|
+
{ "value": "h3", "label": "H3" }, { "value": "h4", "label": "H4" }
|
|
237
|
+
], "default": "h2" },
|
|
72
238
|
{ "type": "text", "id": "heading", "label": "Heading", "default": "What our customers say" },
|
|
73
|
-
{ "type": "
|
|
239
|
+
{ "type": "range", "id": "padding_top", "label": "Padding Top (px)", "min": 0, "max": 160, "step": 8, "default": 80 },
|
|
240
|
+
{ "type": "range", "id": "padding_bottom", "label": "Padding Bottom (px)", "min": 0, "max": 160, "step": 8, "default": 80 }
|
|
74
241
|
],
|
|
75
242
|
"blocks": [
|
|
76
243
|
{
|
|
77
244
|
"type": "testimonial",
|
|
78
245
|
"name": "Testimonial",
|
|
79
246
|
"settings": [
|
|
80
|
-
{ "type": "
|
|
247
|
+
{ "type": "range", "id": "rating", "label": "Star Rating", "min": 0, "max": 5, "step": 1, "default": 5 },
|
|
248
|
+
{ "type": "textarea", "id": "quote", "label": "Quote", "default": "This product completely transformed how I work. Absolutely worth every penny." },
|
|
81
249
|
{ "type": "text", "id": "author", "label": "Author Name", "default": "Happy Customer" },
|
|
82
|
-
{ "type": "text", "id": "role", "label": "Role / Title" },
|
|
250
|
+
{ "type": "text", "id": "role", "label": "Role / Title", "default": "Verified Buyer" },
|
|
83
251
|
{ "type": "image_picker", "id": "avatar", "label": "Avatar Image" }
|
|
84
252
|
]
|
|
85
253
|
},
|
|
@@ -87,7 +255,9 @@
|
|
|
87
255
|
],
|
|
88
256
|
"presets": [{
|
|
89
257
|
"name": "Testimonials Slider",
|
|
90
|
-
"blocks": [
|
|
258
|
+
"blocks": [
|
|
259
|
+
{ "type": "testimonial" }, { "type": "testimonial" }, { "type": "testimonial" }
|
|
260
|
+
]
|
|
91
261
|
}]
|
|
92
262
|
}
|
|
93
263
|
{% endschema %}
|
|
@@ -91,3 +91,45 @@ No,Token Name,Category,Value,CSS Variable,Keywords,Usage,Notes
|
|
|
91
91
|
90,font-family-sans,typography,"system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",--font-family-sans,font family sans serif system stack body,font-family: var(--font-family-sans),System sans-serif stack for body text
|
|
92
92
|
91,font-family-serif,typography,"Georgia, 'Times New Roman', serif",--font-family-serif,font family serif classic editorial heading,font-family: var(--font-family-serif),Classic serif stack for editorial headings
|
|
93
93
|
92,font-family-mono,typography,"'SF Mono', 'Fira Code', 'Courier New', monospace",--font-family-mono,font family monospace code technical,font-family: var(--font-family-mono),Monospace stack for code and technical content
|
|
94
|
+
93,color-foreground,color,var(--color-scheme-foreground),--color-foreground,"color foreground text primary scheme","color: var(--color-foreground)",Primary text color mapped to Shopify color_scheme foreground
|
|
95
|
+
94,color-background-scheme,color,var(--color-scheme-background),--color-background-scheme,"color background surface scheme page","background: var(--color-background-scheme)",Page/section background mapped to Shopify color_scheme background
|
|
96
|
+
95,color-primary-scheme,color,var(--color-scheme-primary),--color-primary-scheme,"color primary brand accent cta button scheme","background: var(--color-primary-scheme); color: var(--color-primary-scheme)",Brand primary / CTA buttons mapped to Shopify color_scheme primary
|
|
97
|
+
96,color-secondary-scheme,color,var(--color-scheme-secondary),--color-secondary-scheme,"color secondary scheme complement","color: var(--color-secondary-scheme)",Secondary elements mapped to Shopify color_scheme secondary
|
|
98
|
+
97,color-primary-text,color,var(--color-scheme-primary-text),--color-primary-text,"color text contrast primary on-primary scheme","color: var(--color-primary-text)",Text on primary/brand background for contrast
|
|
99
|
+
98,color-overlay,color,"rgba(var(--color-foreground-rgb), 0.5)",--color-overlay,"color overlay modal hero backdrop dim","background: var(--color-overlay)",Semi-transparent overlay for modals and hero backgrounds
|
|
100
|
+
99,color-border-subtle,color,"rgba(var(--color-foreground-rgb), 0.1)",--color-border-subtle,"color border divider line subtle thin","border-color: var(--color-border-subtle)",Subtle borders and dividers using foreground RGB
|
|
101
|
+
100,color-surface-elevated,color,"color-mix(in srgb, var(--color-scheme-background) 95%, var(--color-scheme-foreground))",--color-surface-elevated,"color surface card elevated panel raised","background: var(--color-surface-elevated)",Elevated surfaces / cards; slightly different from page background
|
|
102
|
+
101,color-muted,color,"rgba(var(--color-foreground-rgb), 0.6)",--color-muted,"color muted secondary text subdued hint","color: var(--color-muted)",Muted/secondary text color at 60% opacity
|
|
103
|
+
102,color-success-semantic,color,#16a34a,--color-success-semantic,"color success green status positive valid","color: var(--color-success-semantic); background: var(--color-success-semantic)",Success states; accessible green
|
|
104
|
+
103,color-warning-semantic,color,#ca8a04,--color-warning-semantic,"color warning yellow status caution alert","color: var(--color-warning-semantic); background: var(--color-warning-semantic)",Warning states; accessible amber
|
|
105
|
+
104,color-error-semantic,color,#dc2626,--color-error-semantic,"color error red status danger invalid negative","color: var(--color-error-semantic); border-color: var(--color-error-semantic)",Error states; accessible red
|
|
106
|
+
105,color-focus-ring-semantic,color,var(--color-scheme-primary),--color-focus-ring-semantic,"color focus ring accessibility keyboard outline","outline-color: var(--color-focus-ring-semantic)",Focus outline for keyboard navigation using brand primary
|
|
107
|
+
106,font-size-xs-fluid,typography,"clamp(0.7rem, 0.65rem + 0.25vw, 0.75rem)",--font-size-xs-fluid,"font size xs caption small fluid responsive clamp","font-size: var(--font-size-xs-fluid)",Fluid extra small text; captions and fine print; scales with viewport
|
|
108
|
+
107,font-size-sm-fluid,typography,"clamp(0.8rem, 0.75rem + 0.25vw, 0.875rem)",--font-size-sm-fluid,"font size sm label small fluid responsive clamp","font-size: var(--font-size-sm-fluid)",Fluid small text; labels and metadata; scales with viewport
|
|
109
|
+
108,font-size-base-fluid,typography,"clamp(0.9rem, 0.85rem + 0.25vw, 1rem)",--font-size-base-fluid,"font size base body paragraph fluid responsive clamp","font-size: var(--font-size-base-fluid)",Fluid body text; responsive base size
|
|
110
|
+
109,font-size-md-fluid,typography,"clamp(1rem, 0.9rem + 0.5vw, 1.125rem)",--font-size-md-fluid,"font size md medium fluid responsive clamp lead","font-size: var(--font-size-md-fluid)",Fluid medium text; slightly larger body and lead text
|
|
111
|
+
110,font-size-lg-fluid,typography,"clamp(1.1rem, 1rem + 0.5vw, 1.25rem)",--font-size-lg-fluid,"font size lg large fluid responsive clamp heading","font-size: var(--font-size-lg-fluid)",Fluid large text; small headings and prominent labels
|
|
112
|
+
111,font-size-xl-fluid,typography,"clamp(1.25rem, 1rem + 1.25vw, 1.75rem)",--font-size-xl-fluid,"font size xl heading h4 fluid responsive clamp","font-size: var(--font-size-xl-fluid)",Fluid H4 headings; scales from 1.25rem to 1.75rem
|
|
113
|
+
112,font-size-2xl-fluid,typography,"clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem)",--font-size-2xl-fluid,"font size 2xl heading h3 fluid responsive clamp","font-size: var(--font-size-2xl-fluid)",Fluid H3 headings; scales from 1.5rem to 2.25rem
|
|
114
|
+
113,font-size-3xl-fluid,typography,"clamp(1.875rem, 1.5rem + 1.875vw, 3rem)",--font-size-3xl-fluid,"font size 3xl heading h2 fluid responsive clamp","font-size: var(--font-size-3xl-fluid)",Fluid H2 headings; scales from 1.875rem to 3rem
|
|
115
|
+
114,font-size-4xl-fluid,typography,"clamp(2.25rem, 1.75rem + 2.5vw, 4rem)",--font-size-4xl-fluid,"font size 4xl heading h1 fluid responsive clamp hero","font-size: var(--font-size-4xl-fluid)",Fluid H1 headings; scales from 2.25rem to 4rem for maximum impact
|
|
116
|
+
115,font-weight-normal-scale,typography,400,--font-weight-normal-scale,"font weight normal regular 400 body","font-weight: var(--font-weight-normal-scale)",Normal weight 400 for body text; part of semantic weight scale
|
|
117
|
+
116,font-weight-medium-scale,typography,500,--font-weight-medium-scale,"font weight medium 500 emphasis label","font-weight: var(--font-weight-medium-scale)",Medium weight 500 for UI labels and moderate emphasis
|
|
118
|
+
117,font-weight-bold-scale,typography,700,--font-weight-bold-scale,"font weight bold 700 heading strong","font-weight: var(--font-weight-bold-scale)",Bold weight 700 for headings and strong emphasis
|
|
119
|
+
118,duration-instant,animation,50ms,--duration-instant,"duration instant fast micro feedback toggle checkbox","transition-duration: var(--duration-instant)",Instant feedback transitions for checkboxes and toggles
|
|
120
|
+
119,duration-fast,animation,150ms,--duration-fast,"duration fast hover focus interactive quick","transition-duration: var(--duration-fast)",Fast transitions for hover and focus states
|
|
121
|
+
120,duration-normal,animation,300ms,--duration-normal,"duration normal standard expand reveal transition","transition-duration: var(--duration-normal)",Standard animation duration for expand and reveal effects
|
|
122
|
+
121,duration-slow,animation,500ms,--duration-slow,"duration slow complex modal slide panel","transition-duration: var(--duration-slow)",Slower transitions for complex elements like modals and slide panels
|
|
123
|
+
122,duration-slower,animation,800ms,--duration-slower,"duration slower entrance scroll reveal animation","transition-duration: var(--duration-slower)",Entrance animations for scroll-triggered reveal effects
|
|
124
|
+
123,ease-out,animation,"cubic-bezier(0.4, 0, 0.2, 1)",--ease-out,"easing ease out decelerate standard material","transition-timing-function: var(--ease-out)",Standard deceleration easing; elements entering the screen
|
|
125
|
+
124,ease-in-out,animation,"cubic-bezier(0.4, 0, 0.2, 1)",--ease-in-out,"easing ease in out symmetric balanced","transition-timing-function: var(--ease-in-out)",Symmetric easing for elements moving across the screen
|
|
126
|
+
125,ease-spring,animation,"cubic-bezier(0.34, 1.56, 0.64, 1)",--ease-spring,"easing spring bounce overshoot playful","transition-timing-function: var(--ease-spring)",Bouncy spring easing with slight overshoot for playful interactions
|
|
127
|
+
126,shadow-sm-semantic,shadow,"0 1px 2px rgba(0,0,0,0.05)",--shadow-sm-semantic,"shadow small subtle elevation minimal","box-shadow: var(--shadow-sm-semantic)",Minimal shadow for slight elevation; form inputs and badges
|
|
128
|
+
127,shadow-md-semantic,shadow,"0 4px 6px -1px rgba(0,0,0,0.1)",--shadow-md-semantic,"shadow medium card elevation default","box-shadow: var(--shadow-md-semantic)",Card-level elevation shadow; standard depth for content cards
|
|
129
|
+
128,shadow-lg-semantic,shadow,"0 10px 15px -3px rgba(0,0,0,0.1)",--shadow-lg-semantic,"shadow large dropdown modal overlay floating","box-shadow: var(--shadow-lg-semantic)",Dropdown and modal elevation; floating UI elements
|
|
130
|
+
129,shadow-xl-semantic,shadow,"0 20px 25px -5px rgba(0,0,0,0.1)",--shadow-xl-semantic,"shadow extra large hero overlay dramatic high","box-shadow: var(--shadow-xl-semantic)",Hero and overlay elevation; maximum depth for prominent elements
|
|
131
|
+
130,shadow-glow,shadow,"0 0 15px rgba(var(--color-primary-rgb),0.3)",--shadow-glow,"shadow glow primary cta attention highlight brand","box-shadow: var(--shadow-glow)",Glow effect for CTA buttons using brand primary color RGB
|
|
132
|
+
131,breakpoint-sm-shopify,breakpoint,640px,--breakpoint-sm-shopify,"breakpoint small mobile 640px sm","@media (min-width: 640px) { }",Small breakpoint; mobile landscape and small mobile devices
|
|
133
|
+
132,breakpoint-md-shopify,breakpoint,749px,--breakpoint-md-shopify,"breakpoint medium tablet 749px shopify mobile","@media (min-width: 749px) { }",Shopify Dawn mobile/tablet breakpoint; official Shopify threshold
|
|
134
|
+
133,breakpoint-lg-shopify,breakpoint,990px,--breakpoint-lg-shopify,"breakpoint large desktop 990px shopify desktop","@media (min-width: 990px) { }",Shopify Dawn desktop breakpoint; official Shopify desktop threshold
|
|
135
|
+
134,breakpoint-xl-shopify,breakpoint,1200px,--breakpoint-xl-shopify,"breakpoint extra large wide 1200px desktop wide","@media (min-width: 1200px) { }",Wide desktop breakpoint; large monitor and wide viewport layouts
|
package/assets/scripts/core.py
CHANGED
|
@@ -52,6 +52,11 @@ CSV_CONFIG = {
|
|
|
52
52
|
"file": "settings-profiles.csv",
|
|
53
53
|
"search_cols": ["Section Type", "Setting ID", "Notes"],
|
|
54
54
|
"output_cols": ["Section Type", "Setting ID", "Setting Type", "Label", "Default", "Required", "Notes", "Frequency Rank"]
|
|
55
|
+
},
|
|
56
|
+
"animations": {
|
|
57
|
+
"file": "animations.csv",
|
|
58
|
+
"search_cols": ["name", "use_case", "keywords", "category"],
|
|
59
|
+
"output_cols": ["name", "category", "css_keyframes", "easing", "duration", "trigger", "reduced_motion_fallback", "use_case"]
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
62
|
|
|
@@ -164,7 +169,8 @@ domain_keywords = {
|
|
|
164
169
|
"themes": ["theme", "dawn", "impulse", "impact", "craft", "detect", "dna", "theme profile"],
|
|
165
170
|
"practices": ["best practice", "performance", "accessibility", "seo", "os2", "lazy load", "responsive", "a11y"],
|
|
166
171
|
"block-patterns": ["block", "blocks", "block type", "block config", "block pattern", "block setting"],
|
|
167
|
-
"settings-profiles": ["profile", "settings profile", "recommended settings", "section settings", "setting profile"]
|
|
172
|
+
"settings-profiles": ["profile", "settings profile", "recommended settings", "section settings", "setting profile"],
|
|
173
|
+
"animations": ["animation", "animate", "motion", "transition", "easing", "keyframe", "hover", "scroll", "entrance", "parallax", "fade", "slide", "reveal"]
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Design quality advisory checks — GPU animations, motion, responsive, etc.
|
|
3
|
+
|
|
4
|
+
Each function returns (passed: bool, message: str).
|
|
5
|
+
DESIGN_CHECKS is a list of (name, check_fn) tuples consumed by quality-gate.py.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def check_animation_performance(content):
|
|
12
|
+
"""ADVISORY: Animations should use GPU-accelerated properties only."""
|
|
13
|
+
bad_props = re.findall(
|
|
14
|
+
r'transition[^;]*(?:top|left|right|bottom|width|height|margin|padding)[^;]*;',
|
|
15
|
+
content
|
|
16
|
+
)
|
|
17
|
+
if not bad_props:
|
|
18
|
+
return True, "GPU-accelerated animations (transform/opacity)"
|
|
19
|
+
return False, f"non-GPU animated properties found: use transform instead of top/left/width/height"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def check_reduced_motion(content):
|
|
23
|
+
"""ADVISORY: Should include prefers-reduced-motion when animations are present."""
|
|
24
|
+
has_animation = bool(re.search(r'@keyframes|animation:|transition:', content))
|
|
25
|
+
if not has_animation:
|
|
26
|
+
return True, "no animations — reduced-motion not needed"
|
|
27
|
+
has_reduced_motion = 'prefers-reduced-motion' in content
|
|
28
|
+
if has_reduced_motion:
|
|
29
|
+
return True, "prefers-reduced-motion support present"
|
|
30
|
+
return False, "has animations but missing @media (prefers-reduced-motion: reduce)"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def check_responsive_breakpoints(content):
|
|
34
|
+
"""ADVISORY: Should have at least 2 responsive breakpoints."""
|
|
35
|
+
breakpoints = re.findall(
|
|
36
|
+
r'@media[^{]*(?:max-width|min-width)\s*:\s*(\d+)',
|
|
37
|
+
content
|
|
38
|
+
)
|
|
39
|
+
unique = set(breakpoints)
|
|
40
|
+
count = len(unique)
|
|
41
|
+
if count >= 2:
|
|
42
|
+
return True, f"responsive: {count} breakpoints ({', '.join(sorted(unique, key=int))}px)"
|
|
43
|
+
if count == 1:
|
|
44
|
+
return False, f"only 1 breakpoint ({list(unique)[0]}px) — add tablet/desktop breakpoint (990px)"
|
|
45
|
+
return False, "no responsive breakpoints found — add @media queries for mobile + tablet"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def check_css_custom_properties(content):
|
|
49
|
+
"""ADVISORY: Should use CSS custom properties for colors instead of hardcoded hex."""
|
|
50
|
+
# Isolate CSS portion (before schema block)
|
|
51
|
+
if '{%- schema -%}' in content:
|
|
52
|
+
css_part = content.split('{%- schema -%}')[0]
|
|
53
|
+
elif '{% schema %}' in content:
|
|
54
|
+
css_part = content.split('{% schema %}')[0]
|
|
55
|
+
else:
|
|
56
|
+
css_part = content
|
|
57
|
+
|
|
58
|
+
# Strip Liquid output tags to avoid false positives from {{ section.id }}
|
|
59
|
+
css_part = re.sub(r'\{\{.*?\}\}', '', css_part)
|
|
60
|
+
|
|
61
|
+
hardcoded = re.findall(r'#[0-9a-fA-F]{3,8}\b', css_part)
|
|
62
|
+
# Filter out CSS ID selectors (e.g. #section-xxx) — length >= 4 = color, not selector
|
|
63
|
+
real_hardcoded = [h for h in hardcoded if not h.startswith('#section') and len(h) >= 4]
|
|
64
|
+
if not real_hardcoded:
|
|
65
|
+
return True, "no hardcoded colors in CSS — using custom properties"
|
|
66
|
+
return False, f"{len(real_hardcoded)} hardcoded color(s) in CSS — use CSS custom properties instead"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def check_responsive_images(content):
|
|
70
|
+
"""ADVISORY: Images should use srcset or image_url with width for responsive loading."""
|
|
71
|
+
has_images = bool(re.search(r'<img|image_url|img_url', content))
|
|
72
|
+
if not has_images:
|
|
73
|
+
return True, "no images — srcset not needed"
|
|
74
|
+
has_responsive = bool(re.search(r'srcset|image_url.*width|img_url.*\d+x', content))
|
|
75
|
+
if has_responsive:
|
|
76
|
+
return True, "responsive images (srcset/image_url)"
|
|
77
|
+
return False, "images found but no srcset or image_url width — add responsive image handling"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def check_intersection_observer(content):
|
|
81
|
+
"""ADVISORY: Scroll animations should use Intersection Observer for performance."""
|
|
82
|
+
has_scroll_animation = bool(re.search(
|
|
83
|
+
r'\.is-visible|\.animate|scroll.*animation|animation.*scroll',
|
|
84
|
+
content, re.IGNORECASE
|
|
85
|
+
))
|
|
86
|
+
if not has_scroll_animation:
|
|
87
|
+
return True, "no scroll animations — Intersection Observer not needed"
|
|
88
|
+
has_observer = 'IntersectionObserver' in content
|
|
89
|
+
if has_observer:
|
|
90
|
+
return True, "uses Intersection Observer for scroll animations"
|
|
91
|
+
return False, "scroll animations detected but no Intersection Observer — add for performance"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
DESIGN_CHECKS = [
|
|
95
|
+
("animation_performance", check_animation_performance),
|
|
96
|
+
("reduced_motion", check_reduced_motion),
|
|
97
|
+
("responsive_breakpoints", check_responsive_breakpoints),
|
|
98
|
+
("css_custom_properties", check_css_custom_properties),
|
|
99
|
+
("responsive_images", check_responsive_images),
|
|
100
|
+
("intersection_observer", check_intersection_observer),
|
|
101
|
+
]
|
|
@@ -22,6 +22,16 @@ try:
|
|
|
22
22
|
except (FileNotFoundError, AttributeError):
|
|
23
23
|
pass
|
|
24
24
|
|
|
25
|
+
# Import design quality checks (animation, responsive, a11y)
|
|
26
|
+
_design_mod = None
|
|
27
|
+
try:
|
|
28
|
+
_dc_path = Path(__file__).parent / 'quality-gate-design-checks.py'
|
|
29
|
+
_dc_spec = importlib.util.spec_from_file_location('qg_design', _dc_path)
|
|
30
|
+
_design_mod = importlib.util.module_from_spec(_dc_spec)
|
|
31
|
+
_dc_spec.loader.exec_module(_design_mod)
|
|
32
|
+
except (FileNotFoundError, AttributeError):
|
|
33
|
+
pass
|
|
34
|
+
|
|
25
35
|
# Core checks (PASS/FAIL)
|
|
26
36
|
QUALITY_CHECKS = [
|
|
27
37
|
("schema_valid_json", "Schema block contains valid JSON"),
|
|
@@ -229,6 +239,22 @@ def run_quality_gate(filepath):
|
|
|
229
239
|
warned += 1
|
|
230
240
|
results.append(f"⚠ {description}: ERROR ({e})")
|
|
231
241
|
|
|
242
|
+
# Design quality advisory checks (separate section)
|
|
243
|
+
design_passed = 0
|
|
244
|
+
design_total = 0
|
|
245
|
+
design_results = []
|
|
246
|
+
if _design_mod and hasattr(_design_mod, "DESIGN_CHECKS"):
|
|
247
|
+
for name, check_fn in _design_mod.DESIGN_CHECKS:
|
|
248
|
+
design_total += 1
|
|
249
|
+
try:
|
|
250
|
+
ok, msg = check_fn(content)
|
|
251
|
+
if ok:
|
|
252
|
+
design_passed += 1
|
|
253
|
+
icon = "✓" if ok else "⚠"
|
|
254
|
+
design_results.append(f"{icon} {msg}")
|
|
255
|
+
except Exception as e:
|
|
256
|
+
design_results.append(f"⚠ {name}: ERROR ({e})")
|
|
257
|
+
|
|
232
258
|
total = passed + failed + warned
|
|
233
259
|
summary = f"\n## Quality Gate: {path.name}\n"
|
|
234
260
|
summary += f"**Score:** {passed}/{total} checks passed"
|
|
@@ -237,6 +263,11 @@ def run_quality_gate(filepath):
|
|
|
237
263
|
summary += "\n\n"
|
|
238
264
|
summary += "\n".join(results)
|
|
239
265
|
|
|
266
|
+
if design_results:
|
|
267
|
+
summary += "\n\n--- Design Quality Advisory ---\n"
|
|
268
|
+
summary += "\n".join(design_results)
|
|
269
|
+
summary += f"\n\nDesign Quality: {design_passed}/{design_total} advisory checks passed"
|
|
270
|
+
|
|
240
271
|
if failed == 0:
|
|
241
272
|
summary += "\n\n**Result: PASS** ✓"
|
|
242
273
|
if warned:
|
|
@@ -28,6 +28,13 @@ search_settings_profile = _hm.search_settings_profile
|
|
|
28
28
|
search_theme_dna = _hm.search_theme_dna
|
|
29
29
|
search_design_tokens = _hm.search_design_tokens
|
|
30
30
|
|
|
31
|
+
# Import ux-bridge module (kebab-case filename requires importlib)
|
|
32
|
+
_ub_path = Path(__file__).parent / 'ux-bridge.py'
|
|
33
|
+
_ub_spec = _ilu.spec_from_file_location('ux_bridge', _ub_path)
|
|
34
|
+
_ub_mod = _ilu.module_from_spec(_ub_spec)
|
|
35
|
+
_ub_spec.loader.exec_module(_ub_mod)
|
|
36
|
+
build_ux_context = _ub_mod.build_ux_context
|
|
37
|
+
|
|
31
38
|
TEMPLATE_DIR = Path(__file__).parent.parent / "templates"
|
|
32
39
|
|
|
33
40
|
# UTF-8 stdout
|
|
@@ -99,39 +106,14 @@ def search_best_practices(description, max_results=5):
|
|
|
99
106
|
return "\n".join(output)
|
|
100
107
|
|
|
101
108
|
|
|
102
|
-
def try_ui_ux_bridge(ui_style_keywords):
|
|
103
|
-
"""Optional: query ui-ux-pro-max if available. Returns empty string if N/A."""
|
|
104
|
-
try:
|
|
105
|
-
ux_search_path = Path(__file__).parent.parent.parent.parent / ".claude" / "skills" / "ui-ux-pro-max" / "scripts" / "core.py"
|
|
106
|
-
if not ux_search_path.exists():
|
|
107
|
-
ux_search_path = Path(__file__).parent.parent.parent.parent / ".research" / "ui-ux-pro-max-skill" / "src" / "ui-ux-pro-max" / "scripts" / "core.py"
|
|
108
|
-
|
|
109
|
-
if ux_search_path.exists():
|
|
110
|
-
import importlib.util
|
|
111
|
-
spec = importlib.util.spec_from_file_location("ux_core", ux_search_path)
|
|
112
|
-
ux_module = importlib.util.module_from_spec(spec)
|
|
113
|
-
spec.loader.exec_module(ux_module)
|
|
114
|
-
result = ux_module.search(ui_style_keywords, domain="style", max_results=2)
|
|
115
|
-
if result.get("results"):
|
|
116
|
-
lines = ["<design_recommendations>", "**UI/UX Style Recommendations:**"]
|
|
117
|
-
for r in result["results"]:
|
|
118
|
-
lines.append(f"- {r.get('Style Category', '')}: {r.get('Keywords', '')}")
|
|
119
|
-
lines.append(f" Effects: {r.get('Effects & Animation', '')}")
|
|
120
|
-
lines.append("</design_recommendations>")
|
|
121
|
-
return "\n".join(lines)
|
|
122
|
-
except Exception:
|
|
123
|
-
pass
|
|
124
|
-
# Return empty string instead of N/A to avoid wasting prompt tokens
|
|
125
|
-
return ""
|
|
126
|
-
|
|
127
|
-
|
|
128
109
|
def _strip_empty_xml_tags(content):
|
|
129
110
|
"""Remove XML tags whose body is empty or whitespace-only"""
|
|
130
111
|
return re.sub(r'<([\w-]+)>\s*</\1>', '', content)
|
|
131
112
|
|
|
132
113
|
|
|
133
114
|
def assemble_context(name, description, theme_profile, component, schema,
|
|
134
|
-
practices,
|
|
115
|
+
practices, design_system_ctx="", animation_ctx="",
|
|
116
|
+
ux_guidelines_ctx="", block_patterns="",
|
|
135
117
|
settings_profile="", theme_dna="",
|
|
136
118
|
design_tokens="", refinement=""):
|
|
137
119
|
"""Merge all context into generation prompt"""
|
|
@@ -146,7 +128,9 @@ def assemble_context(name, description, theme_profile, component, schema,
|
|
|
146
128
|
content = content.replace("{{ component_pattern_content }}", component)
|
|
147
129
|
content = content.replace("{{ schema_search_results }}", schema)
|
|
148
130
|
content = content.replace("{{ best_practices_results }}", practices)
|
|
149
|
-
content = content.replace("{{
|
|
131
|
+
content = content.replace("{{ design_system_context }}", design_system_ctx)
|
|
132
|
+
content = content.replace("{{ animation_framework_context }}", animation_ctx)
|
|
133
|
+
content = content.replace("{{ ux_guidelines_context }}", ux_guidelines_ctx)
|
|
150
134
|
content = content.replace("{{ block_patterns_results }}", block_patterns)
|
|
151
135
|
content = content.replace("{{ settings_profile_results }}", settings_profile)
|
|
152
136
|
content = content.replace("{{ theme_dna_context }}", theme_dna)
|
|
@@ -175,7 +159,7 @@ def main():
|
|
|
175
159
|
component = search_components(f"{args.name} {args.description}")
|
|
176
160
|
schema = search_schema_settings(f"shopify section settings {args.description}")
|
|
177
161
|
practices = search_best_practices(f"shopify section {args.name} best practices")
|
|
178
|
-
|
|
162
|
+
ux_ctx = build_ux_context(args.name, args.description)
|
|
179
163
|
blocks = search_block_patterns(f"{args.name} {args.description}")
|
|
180
164
|
profile = search_settings_profile(args.name)
|
|
181
165
|
dna = search_theme_dna(args.name)
|
|
@@ -203,8 +187,13 @@ def main():
|
|
|
203
187
|
f"```liquid\n{existing[:3000]}\n```\n</refinement>")
|
|
204
188
|
|
|
205
189
|
context = assemble_context(args.name, args.description, theme, component, schema,
|
|
206
|
-
practices,
|
|
207
|
-
|
|
190
|
+
practices,
|
|
191
|
+
design_system_ctx=ux_ctx.get("design_system", ""),
|
|
192
|
+
animation_ctx=ux_ctx.get("animations", ""),
|
|
193
|
+
ux_guidelines_ctx=ux_ctx.get("ux_guidelines", ""),
|
|
194
|
+
block_patterns=blocks, settings_profile=profile,
|
|
195
|
+
theme_dna=dna, design_tokens=tokens,
|
|
196
|
+
refinement=refinement)
|
|
208
197
|
print(context)
|
|
209
198
|
|
|
210
199
|
|