You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

400 line
13 KiB

  1. {% macro product_image_square(website_image, css_class="") %}
  2. <div class="product-image product-image-square h-100 rounded
  3. {% if not website_image -%} missing-image {%- endif %} {{ css_class }}"
  4. {% if website_image -%}
  5. style="background-image: url('{{ frappe.utils.quoted(website_image) | abs_url }}');"
  6. {%- endif %}>
  7. </div>
  8. {% endmacro %}
  9. {% macro product_image(website_image, css_class="product-image", alt="", no_border=False) %}
  10. <div class="{{ 'border' if not no_border else ''}} text-center rounded {{ css_class }}" style="overflow: hidden;">
  11. {% if website_image %}
  12. <img itemprop="image" class="website-image h-100 w-100" alt="{{ alt }}" src="{{ frappe.utils.quoted(website_image) | abs_url }}">
  13. {% else %}
  14. <div class="card-img-top no-image-item">
  15. {{ frappe.utils.get_abbr(alt) or "NA" }}
  16. </div>
  17. {% endif %}
  18. </div>
  19. {% endmacro %}
  20. {% macro media_image(website_image, name, css_class="") %}
  21. <div class="product-image sidebar-image-wrapper {{ css_class }}">
  22. {% if not website_image -%}
  23. <div class="sidebar-standard-image"> <div class="standard-image" style="background-color: rgb(250, 251, 252);">{{name}}</div> </div>
  24. {%- endif %}
  25. {% if website_image -%}
  26. <a href="{{ frappe.utils.quoted(website_image) }}">
  27. <img itemprop="image" src="{{ frappe.utils.quoted(website_image) | abs_url }}"
  28. class="img-responsive img-thumbnail sidebar-image" style="min-height:100%; min-width:100%;">
  29. </a>
  30. {%- endif %}
  31. </div>
  32. {% endmacro %}
  33. {% macro render_homepage_section(section) %}
  34. {% if section.section_based_on == 'Custom HTML' and section.section_html %}
  35. {{ section.section_html }}
  36. {% elif section.section_based_on == 'Cards' %}
  37. <section class="container my-5">
  38. <h3>{{ section.name }}</h3>
  39. <div class="row">
  40. {% for card in section.section_cards %}
  41. <div class="col-md-{{ section.column_value }} mb-4">
  42. <div class="card h-100 justify-content-between">
  43. {% if card.image %}
  44. <img class="card-img-top h-75" src="{{ card.image }}" loading="lazy" alt="{{ card.title }}"></img>
  45. {% endif %}
  46. <div class="card-body">
  47. <h5 class="card-title">{{ card.title }}</h5>
  48. <p class="card-subtitle mb-2 text-muted">{{ card.subtitle or '' }}</p>
  49. <p class="card-text">{{ card.content or '' | truncate(140, True) }}</p>
  50. </div>
  51. <div class="card-body flex-grow-0">
  52. <a href="{{ card.route }}" class="card-link">{{ _('More details') }}</a>
  53. </div>
  54. </div>
  55. </div>
  56. {% endfor %}
  57. </div>
  58. </section>
  59. {% endif %}
  60. {% endmacro %}
  61. {%- macro item_card(item, is_featured=False, is_full_width=False, align="Left") -%}
  62. {%- set align_items_class = resolve_class({
  63. 'align-items-end': align == 'Right',
  64. 'align-items-center': align == 'Center',
  65. 'align-items-start': align == 'Left',
  66. }) -%}
  67. {%- set col_size = 3 if is_full_width else 4 -%}
  68. {%- set title = item.web_item_name or item.item_name or item.item_code -%}
  69. {%- set title = title[:50] + "..." if title|len > 50 else title -%}
  70. {%- set image = item.website_image -%}
  71. {%- set description = item.website_description or item.description-%}
  72. {% if is_featured %}
  73. <div class="col-sm-{{ col_size*2 }} item-card">
  74. <div class="card featured-item {{ align_items_class }}" style="height: 360px;">
  75. {% if image %}
  76. <div class="row no-gutters">
  77. <div class="col-md-5 ml-4">
  78. <img class="card-img" src="{{ image }}" alt="{{ title }}">
  79. </div>
  80. <div class="col-md-6">
  81. {{ item_card_body(title, description, item, is_featured, align) }}
  82. </div>
  83. </div>
  84. {% else %}
  85. <div class="col-md-12">
  86. {{ item_card_body(title, description, item, is_featured, align) }}
  87. </div>
  88. {% endif %}
  89. </div>
  90. </div>
  91. {% else %}
  92. <div class="col-sm-{{ col_size }} item-card">
  93. <div class="card {{ align_items_class }}" style="height: 360px;">
  94. {% if image %}
  95. <div class="card-img-container">
  96. <a href="/{{ item.route or '#' }}" style="text-decoration: none;">
  97. <img class="card-img" src="{{ image }}" alt="{{ title }}">
  98. </a>
  99. </div>
  100. {% else %}
  101. <a href="/{{ item.route or '#' }}" style="text-decoration: none;">
  102. <div class="card-img-top no-image">
  103. {{ frappe.utils.get_abbr(title) }}
  104. </div>
  105. </a>
  106. {% endif %}
  107. {{ item_card_body(title, description, item, is_featured, align) }}
  108. </div>
  109. </div>
  110. {% endif %}
  111. {%- endmacro -%}
  112. {%- macro item_card_body(title, description, item, is_featured, align) -%}
  113. {%- set align_class = resolve_class({
  114. 'text-right': align == 'Right',
  115. 'text-center': align == 'Center' and not is_featured,
  116. 'text-left': align == 'Left' or is_featured,
  117. }) -%}
  118. <div class="card-body {{ align_class }}" style="width:100%">
  119. <div class="mt-4">
  120. <a href="/{{ item.route or '#' }}">
  121. <div class="product-title">
  122. {{ title or '' }}
  123. </div>
  124. </a>
  125. </div>
  126. {% if is_featured %}
  127. <div class="product-description ellipsis text-muted" style="white-space: normal;">
  128. {{ description or '' }}
  129. </div>
  130. {% else %}
  131. <div class="product-category">{{ item.item_group or '' }}</div>
  132. {% endif %}
  133. </div>
  134. {%- endmacro -%}
  135. {%- macro wishlist_card(item, settings) %}
  136. {%- set title = item.web_item_name or ''-%}
  137. {%- set title = title[:90] + "..." if title|len > 90 else title -%}
  138. <div class="col-sm-3 wishlist-card">
  139. <div class="card text-center">
  140. <div class="card-img-container">
  141. <a href="/{{ item.route or '#' }}" style="text-decoration: none;">
  142. {% if item.image %}
  143. <img class="card-img" src="{{ item.image }}" alt="{{ title }}">
  144. {% else %}
  145. <div class="card-img-top no-image">
  146. {{ frappe.utils.get_abbr(title) }}
  147. </div>
  148. {% endif %}
  149. </a>
  150. <div class="remove-wish" data-item-code="{{ item.item_code }}">
  151. <svg class="icon icon-md remove-wish-icon">
  152. <use class="close" href="#icon-delete"></use>
  153. </svg>
  154. </div>
  155. </div>
  156. {{ wishlist_card_body(item, title, settings) }}
  157. </div>
  158. </div>
  159. {%- endmacro -%}
  160. {%- macro wishlist_card_body(item, title, settings) %}
  161. <div class="card-body card-body-flex text-left" style="width: 100%;">
  162. <div class="mt-4">
  163. <div class="product-title">{{ title or ''}}</div>
  164. <div class="product-category">{{ item.item_group or '' }}</div>
  165. </div>
  166. <div class="product-price">
  167. {{ item.get("formatted_price") or '' }}
  168. {% if item.get("formatted_mrp") %}
  169. <small class="ml-1 striked-price">
  170. <s>{{ item.formatted_mrp }}</s>
  171. </small>
  172. <small class="ml-1 product-info-green" >
  173. {{ item.discount }} OFF
  174. </small>
  175. {% endif %}
  176. </div>
  177. {% if (item.available and settings.show_stock_availability) or (not settings.show_stock_availability) %}
  178. <!-- Show move to cart button if in stock or if showing stock availability is disabled -->
  179. <button data-item-code="{{ item.item_code}}"
  180. class="btn btn-primary btn-add-to-cart-list btn-add-to-cart mt-2 w-100">
  181. <span class="mr-2">
  182. <svg class="icon icon-md">
  183. <use href="#icon-assets"></use>
  184. </svg>
  185. </span>
  186. {{ _("Move to Cart") }}
  187. </button>
  188. {% else %}
  189. <div class="out-of-stock">
  190. {{ _("Out of stock") }}
  191. </div>
  192. {% endif %}
  193. </div>
  194. {%- endmacro -%}
  195. {%- macro ratings_with_title(avg_rating, title, size, rating_header_class, for_summary=False) -%}
  196. <div class="{{ 'd-flex' if not for_summary else '' }}">
  197. <p class="mr-4 {{ rating_header_class }}">
  198. <span>{{ title }}</span>
  199. </p>
  200. <div class="rating {{ 'ratings-pill' if for_summary else ''}}">
  201. {% for i in range(1,6) %}
  202. {% set fill_class = 'star-click' if i <= avg_rating else '' %}
  203. <svg class="icon icon-{{ size }} {{ fill_class }}">
  204. <use href="#icon-star"></use>
  205. </svg>
  206. {% endfor %}
  207. </div>
  208. </div>
  209. {%- endmacro -%}
  210. {%- macro ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating, for_summary=False, total_reviews=None)-%}
  211. <div class="rating-summary-section mt-4">
  212. <div class="rating-summary-numbers col-3">
  213. <h2 style="font-size: 2rem;">
  214. {{ average_rating or 0 }}
  215. </h2>
  216. <div class="mb-2" style="margin-top: -.5rem;">
  217. {{ frappe.utils.cstr(total_reviews or 0) + " " + _("ratings") }}
  218. </div>
  219. <!-- Ratings Summary -->
  220. {% if reviews %}
  221. {% set rating_title = frappe.utils.cstr(average_rating) + " " + _("out of 5") if not for_summary else ''%}
  222. {{ ratings_with_title(average_whole_rating, rating_title, "md", "rating-summary-title", for_summary) }}
  223. {% endif %}
  224. <div class="mt-2">{{ frappe.utils.cstr(average_rating or 0) + " " + _("out of 5") }}</div>
  225. </div>
  226. <!-- Rating Progress Bars -->
  227. <div class="rating-progress-bar-section col-4 ml-4">
  228. {% for percent in reviews_per_rating %}
  229. <div class="col-sm-4 small rating-bar-title">
  230. {{ loop.index }} star
  231. </div>
  232. <div class="row">
  233. <div class="col-md-7">
  234. <div class="progress rating-progress-bar" title="{{ percent }} % of reviews are {{ loop.index }} star">
  235. <div class="progress-bar progress-bar-cosmetic" role="progressbar"
  236. aria-valuenow="{{ percent }}"
  237. aria-valuemin="0" aria-valuemax="100"
  238. style="width: {{ percent }}%;">
  239. </div>
  240. </div>
  241. </div>
  242. <div class="col-sm-1 small">
  243. {{ percent }}%
  244. </div>
  245. </div>
  246. {% endfor %}
  247. </div>
  248. </div>
  249. {%- endmacro -%}
  250. {%- macro user_review(reviews)-%}
  251. <!-- User Reviews -->
  252. <div class="user-reviews">
  253. {% for review in reviews %}
  254. <div class="mb-3 review">
  255. {{ ratings_with_title(review.rating, _(review.review_title), "sm", "user-review-title") }}
  256. <div class="product-description mb-4">
  257. <p>
  258. {{ _(review.comment) }}
  259. </p>
  260. </div>
  261. <div class="review-signature mb-2">
  262. <span class="reviewer">{{ _(review.customer) }}</span>
  263. <span class="indicator grey" style="--text-on-gray: var(--gray-300);"></span>
  264. <span class="reviewer">{{ review.published_on }}</span>
  265. </div>
  266. </div>
  267. {% endfor %}
  268. </div>
  269. {%- endmacro -%}
  270. {%- macro field_filter_section(filters)-%}
  271. {% for field_filter in filters %}
  272. {%- set item_field = field_filter[0] %}
  273. {%- set values = field_filter[1] %}
  274. <div class="mb-4 filter-block pb-5">
  275. <div class="filter-label mb-3">{{ item_field.label }}</div>
  276. {% if values | len > 20 %}
  277. <!-- show inline filter if values more than 20 -->
  278. <input type="text" class="form-control form-control-sm mb-2 filter-lookup-input" placeholder="Search {{ item_field.label + 's' }}"/>
  279. {% endif %}
  280. {% if values %}
  281. <div class="filter-options">
  282. {% for value in values %}
  283. <div class="filter-lookup-wrapper checkbox" data-value="{{ value }}">
  284. <label for="{{value}}">
  285. <input type="checkbox"
  286. class="product-filter field-filter"
  287. id="{{value}}"
  288. data-filter-name="{{ item_field.fieldname }}"
  289. data-filter-value="{{ value }}"
  290. style="width: 14px !important">
  291. <span class="label-area">{{ value }}</span>
  292. </label>
  293. </div>
  294. {% endfor %}
  295. </div>
  296. {% else %}
  297. <i class="text-muted">{{ _('No values') }}</i>
  298. {% endif %}
  299. </div>
  300. {% endfor %}
  301. {%- endmacro -%}
  302. {%- macro attribute_filter_section(filters)-%}
  303. {% for attribute in filters %}
  304. <div class="mb-4 filter-block pb-5">
  305. <div class="filter-label mb-3">{{ attribute.name }}</div>
  306. {% if attribute.item_attribute_values | len > 20 %}
  307. <!-- show inline filter if values more than 20 -->
  308. <input type="text" class="form-control form-control-sm mb-2 filter-lookup-input" placeholder="Search {{ attribute.name + 's' }}"/>
  309. {% endif %}
  310. {% if attribute.item_attribute_values %}
  311. <div class="filter-options">
  312. {% for attr_value in attribute.item_attribute_values %}
  313. <div class="filter-lookup-wrapper checkbox" data-value="{{ attr_value }}">
  314. <label data-value="{{ attr_value }}">
  315. <input type="checkbox"
  316. class="product-filter attribute-filter"
  317. id="{{ attr_value }}"
  318. data-attribute-name="{{ attribute.name }}"
  319. data-attribute-value="{{ attr_value }}"
  320. style="width: 14px !important"
  321. {% if attr_value.checked %} checked {% endif %}>
  322. <span class="label-area">{{ attr_value }}</span>
  323. </label>
  324. </div>
  325. {% endfor %}
  326. </div>
  327. {% else %}
  328. <i class="text-muted">{{ _('No values') }}</i>
  329. {% endif %}
  330. </div>
  331. {% endfor %}
  332. {%- endmacro -%}
  333. {%- macro recommended_item_row(item)-%}
  334. <div class="recommended-item mb-6 d-flex">
  335. <div class="r-item-image">
  336. {% if item.website_item_thumbnail %}
  337. {{ product_image(item.website_item_thumbnail, css_class="r-product-image", alt="item.website_item_name", no_border=True) }}
  338. {% else %}
  339. <div class="no-image-r-item">
  340. {{ frappe.utils.get_abbr(item.website_item_name) or "NA" }}
  341. </div>
  342. {% endif %}
  343. </div>
  344. <div class="r-item-info">
  345. <a href="/{{ item.route or '#'}}" target="_blank">
  346. {% set title = item.website_item_name %}
  347. {{ title[:70] + "..." if title|len > 70 else title }}
  348. </a>
  349. {% if item.get('price_info') %}
  350. {% set price = item.get('price_info') %}
  351. <div class="mt-2">
  352. <span class="item-price">
  353. {{ price.get('formatted_price') or '' }}
  354. </span>
  355. {% if price.get('formatted_mrp') %}
  356. <br>
  357. <span class="striked-item-price">
  358. <s>MRP {{ price.formatted_mrp }}</s>
  359. </span>
  360. <span class="in-green">
  361. - {{ price.get('formatted_discount_percent') or price.get('formatted_discount_rate')}}
  362. </span>
  363. {% endif %}
  364. </div>
  365. {% endif %}
  366. </div>
  367. </div>
  368. {%- endmacro -%}