@spwig/theme-cli 1.1.0 → 2.0.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/CHANGELOG.md +36 -0
- package/README.md +0 -0
- package/dist/cli.d.ts +0 -0
- package/dist/cli.d.ts.map +0 -0
- package/dist/cli.js +4 -30
- package/dist/cli.js.map +1 -1
- package/dist/commands/component.d.ts +0 -0
- package/dist/commands/component.d.ts.map +0 -0
- package/dist/commands/component.js +0 -0
- package/dist/commands/component.js.map +0 -0
- package/dist/commands/dev.d.ts +0 -0
- package/dist/commands/dev.d.ts.map +0 -0
- package/dist/commands/dev.js +2 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts +5 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +80 -115
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/package.d.ts +0 -0
- package/dist/commands/package.d.ts.map +1 -1
- package/dist/commands/package.js +0 -2
- package/dist/commands/package.js.map +1 -1
- package/dist/commands/validate.d.ts +1 -2
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +10 -112
- package/dist/commands/validate.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/schemas/component_manifest_schema.json +0 -0
- package/dist/schemas/theme_manifest_schema.json +5 -63
- package/dist/templates/assets/logo.svg.template +6 -0
- package/dist/templates/assets/theme.js.template +150 -0
- package/dist/templates/components/blank.template.html.template +0 -0
- package/dist/templates/components/footer.manifest.json.template +0 -0
- package/dist/templates/components/footer.schema.json.template +22 -0
- package/dist/templates/components/footer.styles.css.template +80 -0
- package/dist/templates/components/footer.template.html.template +0 -0
- package/dist/templates/components/header.manifest.json.template +0 -0
- package/dist/templates/components/header.schema.json.template +0 -0
- package/dist/templates/components/header.styles.css.template +104 -0
- package/dist/templates/components/header.template.html.template +0 -0
- package/dist/templates/components/schema.json.template +0 -0
- package/dist/templates/components/section.manifest.json.template +2 -2
- package/dist/templates/components/section.schema.json.template +40 -0
- package/dist/templates/components/section.styles.css.template +60 -0
- package/dist/templates/components/section.template.html.template +0 -0
- package/dist/templates/components/utility.manifest.json.template +0 -0
- package/dist/templates/pages/cart.html.template +104 -0
- package/dist/templates/pages/collection.html.template +86 -0
- package/dist/templates/pages/home.html.template +51 -0
- package/dist/templates/pages/layout.html.template +48 -0
- package/dist/templates/pages/product.html.template +90 -0
- package/dist/templates/presets/footer.json.template +16 -0
- package/dist/templates/presets/header.json.template +16 -0
- package/dist/templates/theme/README.md.template +51 -21
- package/dist/templates/theme/design_tokens.json.template +0 -0
- package/dist/templates/theme/manifest.json.template +6 -28
- package/dist/templates/theme/tokens.json.template +1254 -0
- package/dist/utils/file-system.d.ts +0 -0
- package/dist/utils/file-system.d.ts.map +0 -0
- package/dist/utils/file-system.js +0 -0
- package/dist/utils/file-system.js.map +0 -0
- package/dist/utils/validation.d.ts +0 -0
- package/dist/utils/validation.d.ts.map +0 -0
- package/dist/utils/validation.js +0 -0
- package/dist/utils/validation.js.map +0 -0
- package/package.json +2 -2
- package/schemas/theme_manifest_schema.json +5 -63
- package/schemas/component_manifest_schema.json +0 -221
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* Header Component Styles */
|
|
2
|
+
|
|
3
|
+
.site-header {
|
|
4
|
+
background-color: var(--background-color, #ffffff);
|
|
5
|
+
border-bottom: 1px solid var(--border-color, #e5e7eb);
|
|
6
|
+
padding: var(--spacing-md, 1rem) 0;
|
|
7
|
+
position: sticky;
|
|
8
|
+
top: 0;
|
|
9
|
+
z-index: 100;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.header-content {
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: space-between;
|
|
16
|
+
gap: var(--spacing-md, 1rem);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.header-logo {
|
|
20
|
+
flex-shrink: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.logo-image {
|
|
24
|
+
max-height: 48px;
|
|
25
|
+
width: auto;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.logo-text {
|
|
29
|
+
font-size: var(--heading-size-lg, 1.5rem);
|
|
30
|
+
font-weight: 700;
|
|
31
|
+
color: var(--text-color, #1f2937);
|
|
32
|
+
text-decoration: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.logo-text:hover {
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
color: var(--primary-color, #3b82f6);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.main-navigation {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: var(--spacing-md, 1rem);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.nav-link {
|
|
47
|
+
color: var(--text-color, #1f2937);
|
|
48
|
+
font-weight: 500;
|
|
49
|
+
padding: var(--spacing-xs, 0.5rem) var(--spacing-sm, 0.75rem);
|
|
50
|
+
border-radius: var(--border-radius, 4px);
|
|
51
|
+
transition: background-color 0.2s, color 0.2s;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.nav-link:hover {
|
|
55
|
+
background-color: var(--background-secondary, #f3f4f6);
|
|
56
|
+
color: var(--primary-color, #3b82f6);
|
|
57
|
+
text-decoration: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.header-actions {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
gap: var(--spacing-sm, 0.75rem);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.cart-link {
|
|
67
|
+
position: relative;
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
padding: var(--spacing-xs, 0.5rem);
|
|
71
|
+
color: var(--text-color, #1f2937);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.cart-link:hover {
|
|
75
|
+
color: var(--primary-color, #3b82f6);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.cart-icon {
|
|
79
|
+
width: 24px;
|
|
80
|
+
height: 24px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.cart-count {
|
|
84
|
+
position: absolute;
|
|
85
|
+
top: -4px;
|
|
86
|
+
right: -4px;
|
|
87
|
+
background-color: var(--primary-color, #3b82f6);
|
|
88
|
+
color: white;
|
|
89
|
+
font-size: 0.75rem;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
min-width: 18px;
|
|
92
|
+
height: 18px;
|
|
93
|
+
border-radius: 50%;
|
|
94
|
+
display: flex;
|
|
95
|
+
align-items: center;
|
|
96
|
+
justify-content: center;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Responsive */
|
|
100
|
+
@media (max-width: 768px) {
|
|
101
|
+
.main-navigation {
|
|
102
|
+
display: none;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"settings": [
|
|
3
|
+
{
|
|
4
|
+
"id": "title",
|
|
5
|
+
"type": "text",
|
|
6
|
+
"label": "Title",
|
|
7
|
+
"default": "Welcome"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"id": "description",
|
|
11
|
+
"type": "textarea",
|
|
12
|
+
"label": "Description",
|
|
13
|
+
"default": "Discover our amazing products"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "background_color",
|
|
17
|
+
"type": "color",
|
|
18
|
+
"label": "Background Color",
|
|
19
|
+
"default": "#ffffff"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "show_button",
|
|
23
|
+
"type": "checkbox",
|
|
24
|
+
"label": "Show Button",
|
|
25
|
+
"default": true
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "button_text",
|
|
29
|
+
"type": "text",
|
|
30
|
+
"label": "Button Text",
|
|
31
|
+
"default": "Shop Now"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "button_url",
|
|
35
|
+
"type": "url",
|
|
36
|
+
"label": "Button URL",
|
|
37
|
+
"default": "/products"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* Hero Section Component Styles */
|
|
2
|
+
|
|
3
|
+
.hero-section {
|
|
4
|
+
padding: var(--spacing-xxl, 5rem) 0;
|
|
5
|
+
background-color: var(--background-color, #ffffff);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.hero-content {
|
|
9
|
+
max-width: 800px;
|
|
10
|
+
margin: 0 auto;
|
|
11
|
+
text-align: center;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.hero-title {
|
|
15
|
+
font-family: var(--heading-font, inherit);
|
|
16
|
+
font-size: var(--heading-size-xxl, 3rem);
|
|
17
|
+
font-weight: 700;
|
|
18
|
+
color: var(--text-color, #1f2937);
|
|
19
|
+
margin-bottom: var(--spacing-md, 1rem);
|
|
20
|
+
line-height: 1.2;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.hero-description {
|
|
24
|
+
font-size: var(--text-lg, 1.25rem);
|
|
25
|
+
color: var(--text-secondary, #6b7280);
|
|
26
|
+
margin-bottom: var(--spacing-lg, 2rem);
|
|
27
|
+
line-height: 1.6;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.hero-button {
|
|
31
|
+
display: inline-block;
|
|
32
|
+
padding: var(--spacing-sm, 0.75rem) var(--spacing-lg, 2rem);
|
|
33
|
+
background-color: var(--primary-color, #3b82f6);
|
|
34
|
+
color: white;
|
|
35
|
+
font-weight: 600;
|
|
36
|
+
border-radius: var(--border-radius, 4px);
|
|
37
|
+
text-decoration: none;
|
|
38
|
+
transition: background-color 0.2s, transform 0.2s;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.hero-button:hover {
|
|
42
|
+
background-color: var(--primary-dark, #2563eb);
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
transform: translateY(-1px);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Responsive */
|
|
48
|
+
@media (max-width: 768px) {
|
|
49
|
+
.hero-section {
|
|
50
|
+
padding: var(--spacing-xl, 3rem) 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.hero-title {
|
|
54
|
+
font-size: var(--heading-size-xl, 2rem);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.hero-description {
|
|
58
|
+
font-size: var(--text-md, 1rem);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{% extends "layout.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}Shopping Cart - {{ store.name }}{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block body_class %}page-cart{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block content %}
|
|
8
|
+
<div class="cart-page">
|
|
9
|
+
<div class="container">
|
|
10
|
+
<h1 class="page-title">Shopping Cart</h1>
|
|
11
|
+
|
|
12
|
+
{% if cart.items %}
|
|
13
|
+
<div class="cart-layout">
|
|
14
|
+
<!-- Cart Items -->
|
|
15
|
+
<div class="cart-items">
|
|
16
|
+
{% for item in cart.items %}
|
|
17
|
+
<div class="cart-item" data-item-id="{{ item.id }}">
|
|
18
|
+
<div class="item-image">
|
|
19
|
+
{% if item.image %}
|
|
20
|
+
<img src="{{ item.image }}" alt="{{ item.title }}">
|
|
21
|
+
{% endif %}
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="item-details">
|
|
25
|
+
<h3 class="item-title">
|
|
26
|
+
<a href="{{ item.url }}">{{ item.title }}</a>
|
|
27
|
+
</h3>
|
|
28
|
+
{% if item.variant_title %}
|
|
29
|
+
<p class="item-variant">{{ item.variant_title }}</p>
|
|
30
|
+
{% endif %}
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="item-quantity">
|
|
34
|
+
<form action="/cart/update/" method="post" class="quantity-form">
|
|
35
|
+
{% csrf_token %}
|
|
36
|
+
<input type="hidden" name="item_id" value="{{ item.id }}">
|
|
37
|
+
<button type="button" class="qty-btn minus" onclick="this.nextElementSibling.stepDown(); this.form.submit();">-</button>
|
|
38
|
+
<input type="number" name="quantity" value="{{ item.quantity }}" min="0" max="99" class="qty-input">
|
|
39
|
+
<button type="button" class="qty-btn plus" onclick="this.previousElementSibling.stepUp(); this.form.submit();">+</button>
|
|
40
|
+
</form>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="item-price">
|
|
44
|
+
{{ item.line_price|currency }}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<form action="/cart/remove/" method="post" class="remove-form">
|
|
48
|
+
{% csrf_token %}
|
|
49
|
+
<input type="hidden" name="item_id" value="{{ item.id }}">
|
|
50
|
+
<button type="submit" class="remove-btn" aria-label="Remove item">
|
|
51
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
52
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
53
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
54
|
+
</svg>
|
|
55
|
+
</button>
|
|
56
|
+
</form>
|
|
57
|
+
</div>
|
|
58
|
+
{% endfor %}
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<!-- Cart Summary -->
|
|
62
|
+
<div class="cart-summary">
|
|
63
|
+
<h2>Order Summary</h2>
|
|
64
|
+
|
|
65
|
+
<div class="summary-line">
|
|
66
|
+
<span>Subtotal</span>
|
|
67
|
+
<span>{{ cart.subtotal|currency }}</span>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
{% if cart.discount %}
|
|
71
|
+
<div class="summary-line discount">
|
|
72
|
+
<span>Discount</span>
|
|
73
|
+
<span>-{{ cart.discount|currency }}</span>
|
|
74
|
+
</div>
|
|
75
|
+
{% endif %}
|
|
76
|
+
|
|
77
|
+
<div class="summary-line shipping">
|
|
78
|
+
<span>Shipping</span>
|
|
79
|
+
<span>Calculated at checkout</span>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div class="summary-total">
|
|
83
|
+
<span>Total</span>
|
|
84
|
+
<span>{{ cart.total|currency }}</span>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<a href="/checkout/" class="checkout-button">
|
|
88
|
+
Proceed to Checkout
|
|
89
|
+
</a>
|
|
90
|
+
|
|
91
|
+
<a href="/" class="continue-shopping">
|
|
92
|
+
Continue Shopping
|
|
93
|
+
</a>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
{% else %}
|
|
97
|
+
<div class="cart-empty">
|
|
98
|
+
<p>Your cart is empty.</p>
|
|
99
|
+
<a href="/" class="continue-shopping-button">Continue Shopping</a>
|
|
100
|
+
</div>
|
|
101
|
+
{% endif %}
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
{% endblock %}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{% extends "layout.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ collection.title }} - {{ store.name }}{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block meta_description %}{{ collection.description|truncatewords:30 }}{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block body_class %}page-collection{% endblock %}
|
|
8
|
+
|
|
9
|
+
{% block content %}
|
|
10
|
+
<div class="collection-page">
|
|
11
|
+
<div class="container">
|
|
12
|
+
<!-- Collection Header -->
|
|
13
|
+
<div class="collection-header">
|
|
14
|
+
<h1 class="collection-title">{{ collection.title }}</h1>
|
|
15
|
+
{% if collection.description %}
|
|
16
|
+
<p class="collection-description">{{ collection.description }}</p>
|
|
17
|
+
{% endif %}
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<!-- Filters and Sort -->
|
|
21
|
+
<div class="collection-toolbar">
|
|
22
|
+
<div class="filter-controls">
|
|
23
|
+
<!-- Filter implementation depends on your backend -->
|
|
24
|
+
<span class="product-count">{{ products|length }} products</span>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="sort-controls">
|
|
28
|
+
<label for="sort">Sort by:</label>
|
|
29
|
+
<select id="sort" onchange="window.location.href=this.value">
|
|
30
|
+
<option value="?sort=featured">Featured</option>
|
|
31
|
+
<option value="?sort=price-asc">Price: Low to High</option>
|
|
32
|
+
<option value="?sort=price-desc">Price: High to Low</option>
|
|
33
|
+
<option value="?sort=newest">Newest</option>
|
|
34
|
+
<option value="?sort=title-asc">Name: A-Z</option>
|
|
35
|
+
</select>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<!-- Products Grid -->
|
|
40
|
+
<div class="product-grid">
|
|
41
|
+
{% for product in products %}
|
|
42
|
+
<div class="product-card">
|
|
43
|
+
<a href="{{ product.url }}" class="product-link">
|
|
44
|
+
{% if product.image %}
|
|
45
|
+
<img src="{{ product.image }}" alt="{{ product.title }}" class="product-image" loading="lazy">
|
|
46
|
+
{% else %}
|
|
47
|
+
<div class="product-image-placeholder"></div>
|
|
48
|
+
{% endif %}
|
|
49
|
+
|
|
50
|
+
<div class="product-details">
|
|
51
|
+
<h3 class="product-title">{{ product.title }}</h3>
|
|
52
|
+
<div class="product-price">
|
|
53
|
+
{% if product.compare_at_price %}
|
|
54
|
+
<span class="compare-price">{{ product.compare_at_price|currency }}</span>
|
|
55
|
+
{% endif %}
|
|
56
|
+
<span class="current-price">{{ product.price|currency }}</span>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</a>
|
|
60
|
+
</div>
|
|
61
|
+
{% empty %}
|
|
62
|
+
<div class="no-products">
|
|
63
|
+
<p>No products found in this collection.</p>
|
|
64
|
+
</div>
|
|
65
|
+
{% endfor %}
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<!-- Pagination -->
|
|
69
|
+
{% if is_paginated %}
|
|
70
|
+
<nav class="pagination">
|
|
71
|
+
{% if page_obj.has_previous %}
|
|
72
|
+
<a href="?page={{ page_obj.previous_page_number }}" class="page-link">Previous</a>
|
|
73
|
+
{% endif %}
|
|
74
|
+
|
|
75
|
+
<span class="page-info">
|
|
76
|
+
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
|
|
77
|
+
</span>
|
|
78
|
+
|
|
79
|
+
{% if page_obj.has_next %}
|
|
80
|
+
<a href="?page={{ page_obj.next_page_number }}" class="page-link">Next</a>
|
|
81
|
+
{% endif %}
|
|
82
|
+
</nav>
|
|
83
|
+
{% endif %}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
{% endblock %}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{% extends "layout.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ store.name }} - Home{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block body_class %}page-home{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block content %}
|
|
8
|
+
<!-- Hero Section -->
|
|
9
|
+
{% include "components/sections/hero_section/template.html" with settings=page.sections.0.settings %}
|
|
10
|
+
|
|
11
|
+
<!-- Featured Products -->
|
|
12
|
+
<section class="featured-products">
|
|
13
|
+
<div class="container">
|
|
14
|
+
<h2 class="section-title">Featured Products</h2>
|
|
15
|
+
<div class="product-grid">
|
|
16
|
+
{% for product in featured_products %}
|
|
17
|
+
<div class="product-card">
|
|
18
|
+
<a href="{{ product.url }}" class="product-link">
|
|
19
|
+
{% if product.image %}
|
|
20
|
+
<img src="{{ product.image }}" alt="{{ product.title }}" class="product-image">
|
|
21
|
+
{% endif %}
|
|
22
|
+
<h3 class="product-title">{{ product.title }}</h3>
|
|
23
|
+
<p class="product-price">{{ product.price|currency }}</p>
|
|
24
|
+
</a>
|
|
25
|
+
</div>
|
|
26
|
+
{% empty %}
|
|
27
|
+
<p class="no-products">No featured products available.</p>
|
|
28
|
+
{% endfor %}
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</section>
|
|
32
|
+
|
|
33
|
+
<!-- Featured Collections -->
|
|
34
|
+
{% if featured_collections %}
|
|
35
|
+
<section class="featured-collections">
|
|
36
|
+
<div class="container">
|
|
37
|
+
<h2 class="section-title">Shop by Category</h2>
|
|
38
|
+
<div class="collection-grid">
|
|
39
|
+
{% for collection in featured_collections %}
|
|
40
|
+
<a href="{{ collection.url }}" class="collection-card">
|
|
41
|
+
{% if collection.image %}
|
|
42
|
+
<img src="{{ collection.image }}" alt="{{ collection.title }}" class="collection-image">
|
|
43
|
+
{% endif %}
|
|
44
|
+
<h3 class="collection-title">{{ collection.title }}</h3>
|
|
45
|
+
</a>
|
|
46
|
+
{% endfor %}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</section>
|
|
50
|
+
{% endif %}
|
|
51
|
+
{% endblock %}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{% load static %}
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html lang="{{ request.LANGUAGE_CODE|default:'en' }}">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<meta name="description" content="{% block meta_description %}{{ store.description }}{% endblock %}">
|
|
8
|
+
|
|
9
|
+
<title>{% block title %}{{ store.name }}{% endblock %}</title>
|
|
10
|
+
|
|
11
|
+
<!-- Theme Styles -->
|
|
12
|
+
{% if theme_css_url %}
|
|
13
|
+
<link rel="stylesheet" href="{{ theme_css_url }}">
|
|
14
|
+
{% endif %}
|
|
15
|
+
{% if brand_css_url %}
|
|
16
|
+
<link rel="stylesheet" href="{{ brand_css_url }}">
|
|
17
|
+
{% endif %}
|
|
18
|
+
<link rel="stylesheet" href="{% static 'themes/' %}{{ active_theme.slug }}/assets/styles/global.css">
|
|
19
|
+
|
|
20
|
+
<!-- Favicon -->
|
|
21
|
+
{% if store.favicon %}
|
|
22
|
+
<link rel="icon" href="{{ store.favicon }}">
|
|
23
|
+
{% endif %}
|
|
24
|
+
|
|
25
|
+
{% block head_extra %}{% endblock %}
|
|
26
|
+
</head>
|
|
27
|
+
<body class="{% block body_class %}{% endblock %}">
|
|
28
|
+
<!-- Header -->
|
|
29
|
+
{% block header %}
|
|
30
|
+
{% include "components/headers/default_header/template.html" %}
|
|
31
|
+
{% endblock %}
|
|
32
|
+
|
|
33
|
+
<!-- Main Content -->
|
|
34
|
+
<main id="main-content" class="main-content">
|
|
35
|
+
{% block content %}{% endblock %}
|
|
36
|
+
</main>
|
|
37
|
+
|
|
38
|
+
<!-- Footer -->
|
|
39
|
+
{% block footer %}
|
|
40
|
+
{% include "components/footers/default_footer/template.html" %}
|
|
41
|
+
{% endblock %}
|
|
42
|
+
|
|
43
|
+
<!-- Theme Scripts -->
|
|
44
|
+
<script src="{% static 'themes/' %}{{ active_theme.slug }}/assets/theme.js"></script>
|
|
45
|
+
|
|
46
|
+
{% block scripts_extra %}{% endblock %}
|
|
47
|
+
</body>
|
|
48
|
+
</html>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{% extends "layout.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ product.title }} - {{ store.name }}{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block meta_description %}{{ product.description|truncatewords:30 }}{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block body_class %}page-product{% endblock %}
|
|
8
|
+
|
|
9
|
+
{% block content %}
|
|
10
|
+
<div class="product-page">
|
|
11
|
+
<div class="container">
|
|
12
|
+
<div class="product-layout">
|
|
13
|
+
<!-- Product Images -->
|
|
14
|
+
<div class="product-images">
|
|
15
|
+
{% if product.images %}
|
|
16
|
+
<div class="main-image">
|
|
17
|
+
<img src="{{ product.images.0 }}" alt="{{ product.title }}" id="main-product-image">
|
|
18
|
+
</div>
|
|
19
|
+
{% if product.images|length > 1 %}
|
|
20
|
+
<div class="thumbnail-gallery">
|
|
21
|
+
{% for image in product.images %}
|
|
22
|
+
<button class="thumbnail" data-image="{{ image }}">
|
|
23
|
+
<img src="{{ image }}" alt="{{ product.title }} - Image {{ forloop.counter }}">
|
|
24
|
+
</button>
|
|
25
|
+
{% endfor %}
|
|
26
|
+
</div>
|
|
27
|
+
{% endif %}
|
|
28
|
+
{% else %}
|
|
29
|
+
<div class="no-image">
|
|
30
|
+
<span>No image available</span>
|
|
31
|
+
</div>
|
|
32
|
+
{% endif %}
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<!-- Product Info -->
|
|
36
|
+
<div class="product-info">
|
|
37
|
+
<h1 class="product-title">{{ product.title }}</h1>
|
|
38
|
+
|
|
39
|
+
<div class="product-price">
|
|
40
|
+
{% if product.compare_at_price %}
|
|
41
|
+
<span class="compare-price">{{ product.compare_at_price|currency }}</span>
|
|
42
|
+
{% endif %}
|
|
43
|
+
<span class="current-price">{{ product.price|currency }}</span>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="product-description">
|
|
47
|
+
{{ product.description|safe }}
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- Add to Cart Form -->
|
|
51
|
+
<form action="/cart/add/" method="post" class="add-to-cart-form">
|
|
52
|
+
{% csrf_token %}
|
|
53
|
+
<input type="hidden" name="product_id" value="{{ product.id }}">
|
|
54
|
+
|
|
55
|
+
<!-- Variant Selector -->
|
|
56
|
+
{% if product.variants|length > 1 %}
|
|
57
|
+
<div class="variant-selector">
|
|
58
|
+
<label for="variant">Select Option:</label>
|
|
59
|
+
<select name="variant_id" id="variant" required>
|
|
60
|
+
{% for variant in product.variants %}
|
|
61
|
+
<option value="{{ variant.id }}" {% if not variant.available %}disabled{% endif %}>
|
|
62
|
+
{{ variant.title }} - {{ variant.price|currency }}
|
|
63
|
+
{% if not variant.available %}(Sold out){% endif %}
|
|
64
|
+
</option>
|
|
65
|
+
{% endfor %}
|
|
66
|
+
</select>
|
|
67
|
+
</div>
|
|
68
|
+
{% else %}
|
|
69
|
+
<input type="hidden" name="variant_id" value="{{ product.variants.0.id }}">
|
|
70
|
+
{% endif %}
|
|
71
|
+
|
|
72
|
+
<!-- Quantity -->
|
|
73
|
+
<div class="quantity-selector">
|
|
74
|
+
<label for="quantity">Quantity:</label>
|
|
75
|
+
<input type="number" name="quantity" id="quantity" value="1" min="1" max="99">
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<button type="submit" class="add-to-cart-button" {% if not product.available %}disabled{% endif %}>
|
|
79
|
+
{% if product.available %}
|
|
80
|
+
Add to Cart
|
|
81
|
+
{% else %}
|
|
82
|
+
Sold Out
|
|
83
|
+
{% endif %}
|
|
84
|
+
</button>
|
|
85
|
+
</form>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
{% endblock %}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{displayName}} Footer",
|
|
3
|
+
"description": "Custom footer preset for {{displayName}} theme",
|
|
4
|
+
"layout_type": "standard",
|
|
5
|
+
"zone_layouts": {
|
|
6
|
+
"main-footer": ["left", "center", "right"],
|
|
7
|
+
"bottom-bar": ["left", "right"]
|
|
8
|
+
},
|
|
9
|
+
"widget_placements": [
|
|
10
|
+
{"widget_type": "text", "zone": "main-footer_left", "order": 0},
|
|
11
|
+
{"widget_type": "links", "zone": "main-footer_center", "order": 0},
|
|
12
|
+
{"widget_type": "newsletter", "zone": "main-footer_right", "order": 0},
|
|
13
|
+
{"widget_type": "social", "zone": "bottom-bar_left", "order": 0},
|
|
14
|
+
{"widget_type": "text", "zone": "bottom-bar_right", "order": 0, "config": {"content": "© {{year}} {{displayName}}. All rights reserved."}}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{displayName}} Header",
|
|
3
|
+
"description": "Custom header preset for {{displayName}} theme",
|
|
4
|
+
"layout_type": "classic",
|
|
5
|
+
"is_sticky": true,
|
|
6
|
+
"enable_notification_zone": false,
|
|
7
|
+
"zone_layouts": {
|
|
8
|
+
"main-header": ["left", "center", "right"]
|
|
9
|
+
},
|
|
10
|
+
"widget_placements": [
|
|
11
|
+
{"widget_type": "logo", "zone": "main-header_left", "order": 0},
|
|
12
|
+
{"widget_type": "search", "zone": "main-header_center", "order": 0},
|
|
13
|
+
{"widget_type": "cart", "zone": "main-header_right", "order": 0},
|
|
14
|
+
{"widget_type": "account", "zone": "main-header_right", "order": 1}
|
|
15
|
+
]
|
|
16
|
+
}
|