workarea-swatches 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +20 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
- data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.gitignore +21 -0
- data/CHANGELOG.md +121 -0
- data/CODE_OF_CONDUCT.md +3 -0
- data/CONTRIBUTING.md +3 -0
- data/Gemfile +17 -0
- data/LICENSE +52 -0
- data/README.md +40 -0
- data/Rakefile +60 -0
- data/app/assets/javascripts/workarea/storefront/swatches/modules/product_summary_swatches.js +63 -0
- data/app/assets/stylesheets/workarea/storefront/swatches/components/_option_button.scss +17 -0
- data/app/assets/stylesheets/workarea/storefront/swatches/components/_swatch_facet.scss +25 -0
- data/app/assets/stylesheets/workarea/storefront/swatches/components/_swatch_options.scss +54 -0
- data/app/controllers/workarea/admin/catalog_product_swatches_controller.rb +47 -0
- data/app/controllers/workarea/admin/catalog_swatches_controller.rb +48 -0
- data/app/controllers/workarea/storefront/products_controller.decorator +12 -0
- data/app/helpers/workarea/storefront/swatches_helper.rb +84 -0
- data/app/models/workarea/catalog/product.decorator +7 -0
- data/app/models/workarea/catalog/product_swatch.rb +10 -0
- data/app/models/workarea/catalog/swatch.rb +37 -0
- data/app/models/workarea/search/settings.decorator +8 -0
- data/app/queries/workarea/search/category_browse.decorator +7 -0
- data/app/queries/workarea/search/product_search.decorator +7 -0
- data/app/queries/workarea/search/swatched_facets.rb +19 -0
- data/app/queries/workarea/search/swatches_facet.rb +13 -0
- data/app/seeds/workarea/swatches_seeds.rb +37 -0
- data/app/view_models/workarea/storefront/product_templates/swatches_view_model.rb +57 -0
- data/app/views/workarea/admin/activities/_catalog_product_swatch_create.html.haml +10 -0
- data/app/views/workarea/admin/activities/_catalog_product_swatch_destroy.html.haml +10 -0
- data/app/views/workarea/admin/activities/_catalog_swatch_create.html.haml +12 -0
- data/app/views/workarea/admin/activities/_catalog_swatch_destroy.html.haml +10 -0
- data/app/views/workarea/admin/catalog_product_swatches/edit.html.haml +52 -0
- data/app/views/workarea/admin/catalog_product_swatches/index.html.haml +65 -0
- data/app/views/workarea/admin/catalog_products/_swatches_card.html.haml +27 -0
- data/app/views/workarea/admin/catalog_swatches/_primary_navigation.html.haml +1 -0
- data/app/views/workarea/admin/catalog_swatches/index.html.haml +78 -0
- data/app/views/workarea/api/storefront/facets/_swatches.json.jbuilder +17 -0
- data/app/views/workarea/storefront/facets/_swatches.html.haml +14 -0
- data/app/views/workarea/storefront/products/_swatch_summary.html.haml +17 -0
- data/app/views/workarea/storefront/products/templates/_swatches.html.haml +79 -0
- data/bin/rails +19 -0
- data/config/initializers/dragonfly.rb +11 -0
- data/config/initializers/workarea.rb +40 -0
- data/config/locales/en.yml +52 -0
- data/config/routes.rb +15 -0
- data/lib/tasks/swatches_tasks.rake +4 -0
- data/lib/workarea/swatches.rb +11 -0
- data/lib/workarea/swatches/engine.rb +12 -0
- data/lib/workarea/swatches/version.rb +5 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +4 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +30 -0
- data/test/dummy/bin/update +26 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/config/application.rb +30 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +51 -0
- data/test/dummy/config/environments/production.rb +88 -0
- data/test/dummy/config/environments/test.rb +44 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/test/dummy/config/initializers/assets.rb +14 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/workarea.rb +5 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
- data/test/dummy/config/locales/en.yml +33 -0
- data/test/dummy/config/puma.rb +56 -0
- data/test/dummy/config/routes.rb +5 -0
- data/test/dummy/config/secrets.yml +32 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/db/seeds.rb +2 -0
- data/test/dummy/log/.keep +0 -0
- data/test/factories/workarea/swatches.rb +14 -0
- data/test/integration/workarea/admin/product_swatches_integration_test.rb +43 -0
- data/test/integration/workarea/admin/swatches_integration_test.rb +37 -0
- data/test/integration/workarea/storefront/swatches_integration_test.rb +72 -0
- data/test/system/workarea/admin/swatches_system_test.rb +58 -0
- data/test/system/workarea/storefront/browse_swatches_system_test.rb +50 -0
- data/test/system/workarea/storefront/swatches_system_test.rb +101 -0
- data/test/teaspoon_env.rb +6 -0
- data/test/test_helper.rb +10 -0
- data/test/view_models/workarea/storefront/product_templates/swatches_view_model_test.rb +74 -0
- data/workarea-swatches.gemspec +19 -0
- metadata +147 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
/*------------------------------------*\
|
2
|
+
#OPTION-BUTTON
|
3
|
+
\*------------------------------------*/
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Extend the `.option-button` class from Workarea to include a swatch option.
|
7
|
+
*
|
8
|
+
* 1. These dimensions match the :small_thumb processor as configured out of the
|
9
|
+
* box
|
10
|
+
*/
|
11
|
+
$option-button-swatch-height: 60px !default; /* [1] */
|
12
|
+
$option-button-swatch-width: 60px !default; /* [1] */
|
13
|
+
|
14
|
+
.option-button__swatch {
|
15
|
+
height: $option-button-swatch-height;
|
16
|
+
width: $option-button-swatch-width;
|
17
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/*------------------------------------*\
|
2
|
+
#SWATCH-FACET
|
3
|
+
\*------------------------------------*/
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Each `.swatch-facet` also receives an ID modifier class, in order to offer
|
7
|
+
* more granular control over the component, if needed. Since this is a
|
8
|
+
* dynamically generated value, they are not listed here.
|
9
|
+
*/
|
10
|
+
|
11
|
+
$swatch-facet-height: 20px !default;
|
12
|
+
$swatch-facet-width: 20px !default;
|
13
|
+
|
14
|
+
.swatch-facet {
|
15
|
+
display: inline-block;
|
16
|
+
width: $swatch-facet-width;
|
17
|
+
height: $swatch-facet-height;
|
18
|
+
text-decoration: none;
|
19
|
+
vertical-align: middle;
|
20
|
+
}
|
21
|
+
|
22
|
+
.swatch-facet--hex {}
|
23
|
+
.swatch-facet--image {}
|
24
|
+
.swatch-facet--empty {}
|
25
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
/*------------------------------------*\
|
2
|
+
#SWATCH-OPTIONS
|
3
|
+
\*------------------------------------*/
|
4
|
+
|
5
|
+
$swatch-options-outline: 1px solid $light-gray !default;
|
6
|
+
$swatch-options-selected-outline: 1px solid $highlight-color !default;
|
7
|
+
|
8
|
+
.swatch-options {}
|
9
|
+
|
10
|
+
.swatch-options--small {}
|
11
|
+
|
12
|
+
.swatch-options__label {
|
13
|
+
margin: 0;
|
14
|
+
}
|
15
|
+
|
16
|
+
.swatch-options__group {
|
17
|
+
@extend %inline-list;
|
18
|
+
}
|
19
|
+
|
20
|
+
.swatch-options__swatch {
|
21
|
+
position: relative;
|
22
|
+
margin: 0 0 $spacing-unit;
|
23
|
+
width: 44px;
|
24
|
+
height: 44px;
|
25
|
+
outline: $swatch-options-outline;
|
26
|
+
|
27
|
+
& + & {
|
28
|
+
margin-left: $spacing-unit;
|
29
|
+
}
|
30
|
+
|
31
|
+
.swatch-options--small & {
|
32
|
+
margin-top: $spacing-unit;
|
33
|
+
margin-bottom: 0;
|
34
|
+
width: 22px;
|
35
|
+
height: 22px;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
.swatch-options__swatch--selected {
|
40
|
+
outline: $swatch-options-selected-outline;
|
41
|
+
}
|
42
|
+
|
43
|
+
.swatch-options__swatch-button,
|
44
|
+
.swatch-options__swatch-button-image,
|
45
|
+
.swatch-options__swatch-button-text {
|
46
|
+
display: block;
|
47
|
+
position: absolute;
|
48
|
+
top: 0;
|
49
|
+
right: 0;
|
50
|
+
bottom: 0;
|
51
|
+
left: 0;
|
52
|
+
}
|
53
|
+
|
54
|
+
.swatch-options__swatch-name {}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Admin
|
3
|
+
class CatalogProductSwatchesController < Admin::ApplicationController
|
4
|
+
required_permissions :catalog
|
5
|
+
before_action :find_product
|
6
|
+
|
7
|
+
def index
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
@swatch = @product.swatches.build(params[:swatch])
|
12
|
+
|
13
|
+
if @swatch.save
|
14
|
+
flash[:success] = t('workarea.admin.catalog_product_swatches.flash_messages.saved')
|
15
|
+
redirect_to catalog_product_swatches_path(@product)
|
16
|
+
else
|
17
|
+
render :index, status: :unprocessable_entity
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def update
|
22
|
+
@swatch = @product.swatches.find(params[:id])
|
23
|
+
|
24
|
+
if @swatch.update_attributes(params[:swatch])
|
25
|
+
flash[:success] = t('workarea.admin.catalog_product_swatches.flash_messages.saved')
|
26
|
+
redirect_to catalog_product_swatches_path(@product)
|
27
|
+
else
|
28
|
+
flash[:error] = t('workarea.admin.catalog_product_swatches.flash_messages.error')
|
29
|
+
render :index
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy
|
34
|
+
@product.swatches.find(params[:id]).destroy
|
35
|
+
flash[:success] = t('workarea.admin.catalog_product_swatches.flash_messages.removed')
|
36
|
+
redirect_to catalog_product_swatches_path(@product)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def find_product
|
42
|
+
model = Catalog::Product.find_by(slug: params[:catalog_product_id])
|
43
|
+
@product = ProductViewModel.wrap(model, view_model_options)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Admin
|
3
|
+
class CatalogSwatchesController < Admin::ApplicationController
|
4
|
+
required_permissions :catalog
|
5
|
+
before_action :find_swatches
|
6
|
+
|
7
|
+
def index
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
@swatch = Catalog::Swatch.new(params[:swatch])
|
12
|
+
|
13
|
+
if @swatch.save
|
14
|
+
flash[:success] = t('workarea.admin.catalog_swatches.flash_messages.saved')
|
15
|
+
redirect_to catalog_swatches_path
|
16
|
+
else
|
17
|
+
flash[:error] = @swatch.errors.full_messages
|
18
|
+
render :index
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def update
|
23
|
+
@swatch = Catalog::Swatch.find(params[:id])
|
24
|
+
|
25
|
+
if @swatch.update_attributes(params[:swatch])
|
26
|
+
flash[:success] = t('workarea.admin.catalog_swatches.flash_messages.saved')
|
27
|
+
redirect_to catalog_swatches_path
|
28
|
+
else
|
29
|
+
flash[:error] = t('workarea.admin.catalog_swatches.flash_messages.error')
|
30
|
+
render :index
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def destroy
|
35
|
+
Catalog::Swatch.find(params[:id]).destroy
|
36
|
+
flash[:success] = t('workarea.admin.catalog_swatches.flash_messages.removed')
|
37
|
+
redirect_to catalog_swatches_path
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def find_swatches
|
43
|
+
@swatches = Catalog::Swatch.all
|
44
|
+
@search_settings = Search::Settings.current
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Storefront::ProductsController, with: :swatches do
|
3
|
+
def summary
|
4
|
+
@product = Storefront::ProductViewModel.wrap(
|
5
|
+
Catalog::Product.find_by(slug: params[:id]),
|
6
|
+
view_model_options
|
7
|
+
)
|
8
|
+
|
9
|
+
render partial: 'summary', locals: { product: @product }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Storefront
|
3
|
+
module SwatchesHelper
|
4
|
+
def render_swatch_option(selection, swatch)
|
5
|
+
id = selection.optionize
|
6
|
+
|
7
|
+
if swatch&.image?
|
8
|
+
image_tag(
|
9
|
+
swatch.image.process(:small_thumb).url,
|
10
|
+
alt: selection,
|
11
|
+
class: "option-button__image option-button__image--#{id}"
|
12
|
+
)
|
13
|
+
elsif swatch&.hex?
|
14
|
+
content_tag(
|
15
|
+
:div,
|
16
|
+
'',
|
17
|
+
class: "option-button__swatch option-button__swatch--#{id}",
|
18
|
+
style: "background-color: #{swatch.hex};"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def render_browse_swatch(selection, swatch)
|
24
|
+
id = selection.optionize
|
25
|
+
|
26
|
+
if swatch&.image?
|
27
|
+
image_tag(
|
28
|
+
swatch.image.process(:small_thumb).url,
|
29
|
+
alt: selection,
|
30
|
+
class: [
|
31
|
+
'swatch-options__swatch-button-image',
|
32
|
+
"swatch-options__swatch-button-image--#{id}"
|
33
|
+
].join(' ')
|
34
|
+
)
|
35
|
+
elsif swatch&.hex?
|
36
|
+
content_tag(
|
37
|
+
:div,
|
38
|
+
'',
|
39
|
+
class: [
|
40
|
+
'swatch-options__swatch-button',
|
41
|
+
"swatch-options__swatch-button--#{id}"
|
42
|
+
].join(' '),
|
43
|
+
style: "background-color: #{swatch.hex};"
|
44
|
+
)
|
45
|
+
else
|
46
|
+
content_tag(
|
47
|
+
:div,
|
48
|
+
selection,
|
49
|
+
class: 'swatch-options__swatch-button-text'
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def render_swatch_facet(selection)
|
55
|
+
id = selection.optionize
|
56
|
+
|
57
|
+
@swatches_cache ||= Catalog::Swatch.all.to_a
|
58
|
+
swatch = @swatches_cache.detect { |s| s.id == id }
|
59
|
+
class_list = "swatch-facet swatch-facet--#{id}"
|
60
|
+
|
61
|
+
if swatch&.image?
|
62
|
+
image_tag(
|
63
|
+
swatch.image.process(:facet_swatch).url,
|
64
|
+
alt: selection,
|
65
|
+
class: "#{class_list} swatch-facet--image"
|
66
|
+
)
|
67
|
+
elsif swatch&.hex?
|
68
|
+
content_tag(
|
69
|
+
:div,
|
70
|
+
'',
|
71
|
+
class: "#{class_list} swatch-facet--hex",
|
72
|
+
style: "background-color: #{swatch.hex};"
|
73
|
+
)
|
74
|
+
else
|
75
|
+
content_tag(
|
76
|
+
:span,
|
77
|
+
'',
|
78
|
+
class: "#{class_list} swatch-facet--empty"
|
79
|
+
)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Catalog
|
3
|
+
class Swatch
|
4
|
+
include ApplicationDocument
|
5
|
+
extend Dragonfly::Model
|
6
|
+
|
7
|
+
field :_id, type: String, default: -> { name.optionize }
|
8
|
+
field :name, type: String
|
9
|
+
field :hex, type: String
|
10
|
+
field :image_name, type: String
|
11
|
+
field :image_uid, type: String
|
12
|
+
|
13
|
+
validates :name, presence: true
|
14
|
+
validates :hex, length: { is: 7, allow_blank: true }
|
15
|
+
validates :id, uniqueness: true
|
16
|
+
|
17
|
+
dragonfly_accessor :image, app: :workarea
|
18
|
+
|
19
|
+
before_validation :normalize_hex
|
20
|
+
|
21
|
+
def image?
|
22
|
+
image.present?
|
23
|
+
end
|
24
|
+
|
25
|
+
def hex?
|
26
|
+
hex.present?
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def normalize_hex
|
32
|
+
return if hex.blank?
|
33
|
+
self.hex = hex.starts_with?('#') ? hex : "##{hex}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Search
|
3
|
+
module SwatchedFacets
|
4
|
+
def facets
|
5
|
+
@swatched_facets ||= begin
|
6
|
+
swatch_facet_names = swatched_facets.map(&:name)
|
7
|
+
without_swatches = super.reject { |f| f.name.in?(swatch_facet_names) }
|
8
|
+
swatched_facets + without_swatches
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def swatched_facets
|
13
|
+
Search::Settings.current.swatch_facets.map do |swatch_facet|
|
14
|
+
SwatchesFacet.new(self, swatch_facet)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Search
|
3
|
+
class SwatchesFacet < TermsFacet
|
4
|
+
# This class exists so we have a specific facet type to allow rendering
|
5
|
+
# a different partial in the storefront to give us the opportunity to show
|
6
|
+
# the swatches
|
7
|
+
|
8
|
+
def type
|
9
|
+
:swatches
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Workarea
|
2
|
+
class SwatchesSeeds
|
3
|
+
COLORS = {
|
4
|
+
red: '#f44336',
|
5
|
+
pink: '#e91e63',
|
6
|
+
purple: '#9c27b0',
|
7
|
+
deep_purple: '#673ab7',
|
8
|
+
indigo: '#3f51b5',
|
9
|
+
blue: '#2196f3',
|
10
|
+
light_blue: '#03a9f4',
|
11
|
+
cyan: '#00bcd4',
|
12
|
+
teal: '#009688',
|
13
|
+
green: '#4caf50',
|
14
|
+
light_green: '#8bc34a',
|
15
|
+
lime: '#cddc39',
|
16
|
+
yellow: '#ffeb3b',
|
17
|
+
amber: '#ffc107',
|
18
|
+
orange: '#ff9800',
|
19
|
+
deep_orange: '#ff5722',
|
20
|
+
brown: '#795548',
|
21
|
+
grey: '#9e9e9e',
|
22
|
+
blue_grey: '#607d8b',
|
23
|
+
white: '#ffffff',
|
24
|
+
black: '#000000'
|
25
|
+
}
|
26
|
+
|
27
|
+
def perform
|
28
|
+
puts 'Adding swatches...'
|
29
|
+
|
30
|
+
COLORS.each do |name, hex|
|
31
|
+
Catalog::Swatch.create!(name: name.to_s.titleize, hex: hex)
|
32
|
+
end
|
33
|
+
|
34
|
+
Search::Settings.current.update_attributes!(swatch_facets: ['Color'])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|