loft 0.1.2 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d229fb260b365c12ff3b3ea01d22d46127a2ef0f
4
- data.tar.gz: 2d134163274e9e5c1c2613e9f436a93cd6eea9a2
3
+ metadata.gz: 7f204fc64713eb740598cd03d4cd32aa11313719
4
+ data.tar.gz: 39d010891c3e501c7321690cdcfe81b4e4ba26f9
5
5
  SHA512:
6
- metadata.gz: 8888002fc78aa83f97d4a848bcc5f37745317070a3bead5d5d7d48992f37695de3fa735fd042f5a5369d53b85e230a50ca82746f5f8d88f30778da83181ede2d
7
- data.tar.gz: 8629e3a75d48bb5bff41e699f13f30b01aaed2193590a1bbdfadb31a38df182171957fc6868ef8e1351e9f50cd39c937c559246f60affe03e227e808f4267d15
6
+ metadata.gz: 8bbe85ed20e0221a0d4776100bfa2a8648816b6ce960d5aeb590990fbcb2586ed29efdef9822c46f811b3a97fb5e6d2aa353e02c7273ecdb6691891e58fccbfc
7
+ data.tar.gz: b612bcbf8a16792e2231b79e250be6ea4c6cf3bfee97c465fda6f8825317a65ed3fa862797747c1a25c5135fe1230aab3eb2130a4904bae35d9981ef7eaee6a1
data/.gitignore CHANGED
@@ -1,2 +1,4 @@
1
1
  *.gem
2
- .DS_Store
2
+ .DS_Store
3
+
4
+ node_modules/
data/Gruntfile.coffee ADDED
@@ -0,0 +1,41 @@
1
+ module.exports = (grunt) ->
2
+ # Project configuration
3
+ grunt.initConfig
4
+ pkg: grunt.file.readJSON('package.json')
5
+ coffee:
6
+ compileBare:
7
+ options:
8
+ bare: true
9
+ files:
10
+ 'build/loft.js': [
11
+ # core
12
+ 'app/assets/javascripts/loft/group-actions.coffee'
13
+ 'app/assets/javascripts/loft/asset-item.coffee'
14
+ 'app/assets/javascripts/loft/module.coffee'
15
+ # redactor
16
+ 'app/assets/javascripts/loft/redactor-loft.coffee'
17
+ # inputs
18
+ 'app/assets/javascripts/loft/input-loft-asset.coffee'
19
+ 'app/assets/javascripts/loft/input-loft-image.coffee'
20
+ ]
21
+
22
+ concat:
23
+ loft:
24
+ src: [
25
+ 'build/loft.js'
26
+ ]
27
+ dest: 'dist/loft.js'
28
+
29
+ clean: [
30
+ 'build'
31
+ ]
32
+
33
+ grunt.loadNpmTasks('grunt-contrib-coffee')
34
+ grunt.loadNpmTasks('grunt-contrib-concat')
35
+ grunt.loadNpmTasks('grunt-contrib-clean')
36
+
37
+ grunt.registerTask('default', ['coffee', 'concat', 'clean'])
38
+
39
+
40
+
41
+
data/README.md CHANGED
@@ -45,10 +45,14 @@ Add to ```admin.scss```:
45
45
  Add to ```admin.coffee``` character configuration object:
46
46
 
47
47
  ```coffee
48
- assets: new Loft('Library', 'asset', '/admin/assets')
48
+ loft: new Loft('Files', 'asset', '/admin/assets')
49
49
  ```
50
50
 
51
51
 
52
+ ## Notes
53
+
54
+ 1. Check out [kraken.io](https://github.com/kraken-io/kraken-ruby) for image optimization.
55
+
52
56
  ## Loft family
53
57
 
54
58
  - [Character](https://github.com/slate-studio/chr): Powerful javascript CMS for apps
@@ -1,10 +1,10 @@
1
1
  #= require loft/group-actions
2
2
  #= require loft/asset-item
3
- #= require loft/type-item
4
3
  #= require loft/module
5
4
 
6
- #= require redactor-loft
7
- #= require input-loft-image
5
+ #= require loft/redactor-loft
6
+ #= require loft/input-loft-asset
7
+ #= require loft/input-loft-image
8
8
 
9
9
  # TODOs:
10
- # - refactor group remove action
10
+ # - refactor group remove action: delete a bunch first, then reload the page
@@ -11,10 +11,44 @@
11
11
  # -----------------------------------------------------------------------------
12
12
  class @LoftAssetItem extends Item
13
13
  constructor: (@module, @path, @object, @config) ->
14
- @$el =$ "<div class='item asset asset-#{ @object.type }' data-id='#{ @object._id }' data-title=''></div>"
14
+ @$el =$ "<div class='item asset asset-#{ @object.type }' data-id='#{ @object._id }'></div>"
15
15
  @render()
16
16
 
17
17
 
18
+ # PRIVATE ===============================================
19
+
20
+ _bind_name_input: ->
21
+ @$nameInput.on 'blur', (e) => @_update_name_if_changed()
22
+ @$nameInput.on 'keyup', (e) =>
23
+ if e.keyCode == 13 then $(e.target).blur()
24
+ if e.keyCode == 27 then @_cancel_name_change()
25
+
26
+
27
+ _edit_name: (e) ->
28
+ @$el.addClass('edit-name')
29
+ @$nameInput.focus().select()
30
+
31
+
32
+ _cancel_name_change: ->
33
+ @$el.removeClass('edit-name')
34
+ name = @$title.html()
35
+ @$nameInput.val(name)
36
+
37
+
38
+ _update_name_if_changed: ->
39
+ @$el.removeClass('edit-name')
40
+ name = @$nameInput.val()
41
+
42
+ if name == @$title.html() then return
43
+ @$title.html(name)
44
+
45
+ @config.arrayStore.update @object._id, { '[name]': name },
46
+ onSuccess: (object) =>
47
+ onError: (errors) => # process errors
48
+
49
+
50
+ # PUBLIC ================================================
51
+
18
52
  render: ->
19
53
  @$el.html('').removeClass('item-folder has-subtitle has-thumbnail')
20
54
 
@@ -40,7 +74,7 @@ class @LoftAssetItem extends Item
40
74
 
41
75
 
42
76
  # input for assets name
43
- name = @$el.attr('data-title')
77
+ name = @$title.text()
44
78
  @$name =$ "<div class='asset-name'></div>"
45
79
  @$nameInput =$ "<input type='text' value='#{ name }' />"
46
80
  @$name.append @$nameInput
@@ -51,36 +85,5 @@ class @LoftAssetItem extends Item
51
85
  @$title.on 'click', (e) => @_edit_name(e)
52
86
 
53
87
 
54
- _bind_name_input: ->
55
- @$nameInput.on 'blur', (e) => @_update_name_if_changed()
56
- @$nameInput.on 'keyup', (e) =>
57
- if e.keyCode == 13 then $(e.target).blur()
58
- if e.keyCode == 27 then @_cancel_name_change()
59
-
60
-
61
- _edit_name: (e) ->
62
- @$el.addClass('edit-name')
63
- @$nameInput.focus().select()
64
-
65
-
66
- _cancel_name_change: ->
67
- @$el.removeClass('edit-name')
68
- name = @$title.html()
69
- @$nameInput.val(name)
70
-
71
-
72
- _update_name_if_changed: ->
73
- @$el.removeClass('edit-name')
74
- name = @$nameInput.val()
75
-
76
- if name == @$title.html() then return
77
- @$title.html(name)
78
-
79
- @config.arrayStore.update @object._id, { '[name]': name },
80
- onSuccess: (object) =>
81
- onError: (errors) => # process errors
82
-
83
-
84
-
85
88
 
86
89
 
@@ -15,6 +15,8 @@ class @LoftGroupActions
15
15
  @_bind_checkboxes()
16
16
 
17
17
 
18
+ # PRIVATE ===============================================
19
+
18
20
  _render: ->
19
21
  @$el =$ "<div class='assets-group-actions' style='display:none;'></div>"
20
22
  @list.$header.append @$el
@@ -95,6 +97,8 @@ class @LoftGroupActions
95
97
  @$el.show()
96
98
 
97
99
 
100
+ # PUBLIC ================================================
101
+
98
102
  hide: ->
99
103
  @$el.hide()
100
104
 
@@ -0,0 +1,11 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Author: Alexander Kravets <alex@slatestudio.com>,
3
+ # Slate Studio (http://www.slatestudio.com)
4
+ #
5
+ # Coding Guide:
6
+ # https://github.com/thoughtbot/guides/tree/master/style/coffeescript
7
+ # -----------------------------------------------------------------------------
8
+
9
+ # -----------------------------------------------------------------------------
10
+ # INPUT LOFT ASSET
11
+ # -----------------------------------------------------------------------------
@@ -41,7 +41,7 @@ class @InputLoftImage extends InputString
41
41
 
42
42
  @$chooseBtn.on 'click', (e) =>
43
43
  e.preventDefault()
44
- chr.modules.assets.showModal 'images', false, (objects) =>
44
+ chr.modules.loft.showModal 'images', false, (objects) =>
45
45
  asset = objects[0]
46
46
  @updateValue(asset.file.url)
47
47
 
@@ -8,32 +8,40 @@
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
  # Loft
11
+ # -----------------------------------------------------------------------------
11
12
  #
12
13
  # Public methods:
13
- # new Loft(title, @resource, @resourcePath)
14
+ # new Loft(title, resource, resourcePath, @arrayStoreClass, @arrayStoreConfig)
14
15
  # showModal(assetType, @selectMultipleAssets, @onAcceptCallback)
15
16
  # closeModal()
16
17
  #
17
18
  # -----------------------------------------------------------------------------
18
19
  class @Loft
19
- constructor: (title, @resource, @resourcePath) ->
20
+ constructor: (title, resource, resourcePath, @arrayStoreClass, @arrayStoreConfig) ->
20
21
  @module = {}
21
22
  @store = {}
22
23
 
24
+ @arrayStoreClass ?= RailsArrayStore
25
+ @arrayStoreConfig ?=
26
+ resource: resource
27
+ path: resourcePath
28
+ sortBy: 'created_at'
29
+ sortReverse: true
30
+ searchable: true
31
+
23
32
  @_uploadsCounter = 0
24
33
 
25
34
  moduleConfig =
26
35
  title: title
27
36
  showNestedListsAside: true
28
- itemClass: LoftTypeItem
29
37
  items:
30
- assets_all: @_nested_list_config 'All'
31
- assets_images: @_nested_list_config 'Images', 'image'
32
- assets_text: @_nested_list_config 'Text', 'text'
33
- assets_archives: @_nested_list_config 'Archives', 'archive'
34
- assets_audio: @_nested_list_config 'Audio', 'audio'
35
- assets_video: @_nested_list_config 'Video', 'video'
36
- assets_other: @_nested_list_config 'Other', 'other'
38
+ loft_all: @_nested_list_config 'All'
39
+ loft_images: @_nested_list_config 'Images', 'image'
40
+ loft_text: @_nested_list_config 'Text', 'text'
41
+ loft_archives: @_nested_list_config 'Archives', 'archive'
42
+ loft_audio: @_nested_list_config 'Audio', 'audio'
43
+ loft_video: @_nested_list_config 'Video', 'video'
44
+ loft_other: @_nested_list_config 'Other', 'other'
37
45
 
38
46
  onModuleInit: (module) =>
39
47
  @_initialize_module(module)
@@ -41,9 +49,11 @@ class @Loft
41
49
  return moduleConfig
42
50
 
43
51
 
52
+ # PRIVATE ===============================================
53
+
44
54
  _initialize_module: (module) ->
45
55
  @module = module
46
- @store = @module.nestedLists.assets_all.config.arrayStore
56
+ @store = @module.nestedLists.loft_all.config.arrayStore
47
57
 
48
58
  # API method
49
59
  @module.showModal = (assetType, selectMultipleAssets, callback) =>
@@ -55,28 +65,40 @@ class @Loft
55
65
  @module.rootList.$header.prepend @module.rootList.$modalCloseBtn
56
66
  @module.rootList.$modalCloseBtn.on 'click', (e) => e.preventDefault() ; @closeModal()
57
67
 
68
+ # modal types navigation
69
+ @module.rootList.$items.on 'click', 'a', (e) =>
70
+ if @module.$el.hasClass 'module-modal'
71
+ e.preventDefault()
72
+
73
+ $item = $(e.currentTarget)
74
+ listName = $item.attr('href').split('/')[2]
75
+
76
+ @module.activeList.hide()
77
+ @module.showList(listName)
78
+ @module.activeList.updateItems()
79
+
80
+ $item.parent().children('.active').removeClass('active')
81
+ $item.addClass('active')
82
+
58
83
  # enable grid mode as default on desktop/tablet
59
84
  if ! chr.isMobile()
60
85
  @module.$el.addClass('grid-mode')
61
86
 
62
87
 
63
88
  _nested_list_config: (moduleName, assetType) ->
64
- arrayStoreConfig =
65
- resource: @resource
66
- path: @resourcePath
67
- searchable: true
68
- sortBy: 'created_at'
69
- sortReverse: true
89
+ storeConfig = {}
90
+ $.extend(storeConfig, @arrayStoreConfig)
70
91
 
71
92
  if assetType
72
- $.extend(arrayStoreConfig, { urlParams: { by_type: assetType } })
93
+ $.extend(storeConfig, { urlParams: { by_type: assetType } })
73
94
 
74
95
  config =
75
96
  title: moduleName
76
97
  itemTitleField: 'name'
77
98
  itemSubtitleField: 'created_ago'
99
+ showWithParent: true
78
100
  itemClass: LoftAssetItem
79
- arrayStore: new MongosteenArrayStore(arrayStoreConfig)
101
+ arrayStore: new @arrayStoreClass(storeConfig)
80
102
  onListInit: (list) => @_inititialize_list(list)
81
103
  onListShow: (list) => @_clear_assets_selection()
82
104
 
@@ -102,6 +124,12 @@ class @Loft
102
124
  list.$backBtn.after list.$switchMode
103
125
  list.$switchMode.on 'click', (e) => e.preventDefault() ; @module.$el.toggleClass('grid-mode')
104
126
 
127
+ # modal back for mobiles
128
+ list.$header.on 'click', '.back', (e) =>
129
+ if @module.$el.hasClass 'module-modal'
130
+ e.preventDefault()
131
+ @module.showList()
132
+
105
133
 
106
134
  _upload: (file, list) ->
107
135
  obj = {}
@@ -125,11 +153,10 @@ class @Loft
125
153
  if @_uploadsCounter == 0
126
154
  @module.$el.removeClass('assets-uploading')
127
155
 
128
- # update data in list if it's not assets_all,
129
- # in assets_all new objects are added automatically
130
- visibleList = @module.visibleNestedListShownWithParent()
131
- if visibleList.name != 'assets_all'
132
- visibleList.updateItems()
156
+ # update data in list if it's not loft_all,
157
+ # in loft_all new objects are added automatically
158
+ if @module.activeList.name != 'loft_all'
159
+ @module.activeList.updateItems()
133
160
 
134
161
 
135
162
  _clear_assets_selection: ->
@@ -138,6 +165,8 @@ class @Loft
138
165
  list.$items.find('.asset-checkbox').prop('checked', false)
139
166
 
140
167
 
168
+ # PUBLIC ================================================
169
+
141
170
  closeModal: ->
142
171
  @selectMultipleAssets = true
143
172
  @_clear_assets_selection()
@@ -149,13 +178,14 @@ class @Loft
149
178
  showModal: (assetType='all', @selectMultipleAssets=false, @onAcceptCallback=$.noop) ->
150
179
  # modal mode
151
180
  @module.$el.addClass('module-modal')
181
+ # show module
182
+ @module.show()
152
183
  # show nested list
153
- @module.showNestedList("assets_#{ assetType }")
184
+ @module.showList("loft_#{ assetType }")
185
+ @module.activeList.updateItems()
154
186
  # select active item
155
187
  @module.rootList.$items.children().removeClass('active')
156
- @module.rootList.$items.children("[href='#/assets/assets_#{ assetType }']").addClass('active')
157
- # show module
158
- @module.show()
188
+ @module.rootList.$items.children("[href='#/loft/loft_#{ assetType }']").addClass('active')
159
189
 
160
190
 
161
191
 
@@ -23,13 +23,13 @@ RedactorPlugins.loft = ->
23
23
 
24
24
 
25
25
  showImagesModal: ->
26
- chr.modules.assets.showModal 'images', true, (objects) => @loft.insertImages(objects)
26
+ chr.modules.loft.showModal 'images', true, (objects) => @loft.insertImages(objects)
27
27
 
28
28
 
29
29
  # allow multiple assets when no text is selected
30
30
  showAllModal: ->
31
31
  multipleAssets = this.selection.getText() == ''
32
- chr.modules.assets.showModal 'all', multipleAssets, (objects) => @loft.insertFiles(objects)
32
+ chr.modules.loft.showModal 'all', multipleAssets, (objects) => @loft.insertFiles(objects)
33
33
 
34
34
 
35
35
  # if text is selected replace text with <a>{{ text }}</a>
@@ -7,11 +7,6 @@
7
7
 
8
8
  // MIXINS
9
9
 
10
- @mixin iconBase($bgSize, $width, $height) {
11
- background-image: image-url('loft/library@3x.png'); background-size: $bgSize;
12
- display: block; width: $width; height: $height;
13
- }
14
-
15
10
  @mixin iconLabel($title) {
16
11
  &:before {
17
12
  display: block; margin-top: 2.6em;
@@ -21,13 +16,17 @@
21
16
  }
22
17
  }
23
18
 
19
+ @mixin iconBase($bgSize, $width, $height) {
20
+ display: block; background-size: $bgSize; width: $width; height: $height;
21
+ background-image: image-url("loft/library@3x.png");
22
+ }
24
23
 
25
24
  // ASSET TYPE ICONS
26
25
 
27
- .module.assets .list:first-child .items {
26
+ .loft .list:first-child .items {
28
27
  .item {
29
28
  .item-title { margin-left: 2.05em; }
30
- &:before { @include absolutePosition(inherit inherit inherit 1em); content: ''; display: block; }
29
+ &:before { @include position(absolute, null null null 1em); content: ''; display: block; }
31
30
  }
32
31
 
33
32
  .item {
@@ -63,24 +62,24 @@
63
62
 
64
63
  // LIST MODE
65
64
 
66
- .module.assets .list:not(:first-child) .items .item.asset {
65
+ .loft .list:not(:first-child) .items .item.asset {
67
66
  padding-left: 6.25em; // 100px;
68
67
 
69
68
  // checkbox
70
69
  .asset-checkbox {
71
- @include absolutePosition(1.3em inherit inherit 1em); z-index: 1;
72
- input { @include absolutePosition(0px inherit inherit 0px); }
70
+ @include position(absolute, 1.3em null null 1em); z-index: 1;
71
+ input { @include position(absolute, 0px null null 0px); }
73
72
  }
74
73
 
75
74
  // type icon
76
75
  .asset-icon {
77
76
  @include iconBase(64px 224px, 32px, 32px);
78
- @include absolutePosition(12px inherit inherit 3.05em);
77
+ @include position(absolute, 12px null null 3.05em);
79
78
  }
80
79
 
81
80
  // image thumbnail
82
81
  &.asset-image .asset-icon {
83
- @include absolutePosition(8px inherit inherit 2.8em);
82
+ @include position(absolute, 8px null null 2.8em);
84
83
  overflow: hidden; width: 40px; height: 40px; border-radius: 20px;
85
84
  img { height: 100%; }
86
85
  }
@@ -99,8 +98,8 @@
99
98
  .item-title { cursor: pointer; }
100
99
  .asset-name {
101
100
  display: none; z-index: 1;
102
- @include absolutePosition(7px .5em inherit 94px);
103
- input { width: 100%; padding: .1em .3em .3em .3em; @include noFocus();
101
+ @include position(absolute, 7px .5em null 94px);
102
+ input { width: 100%; padding: .1em .3em .3em .3em; @include no-focus-outline;
104
103
  border: 1px solid $stableColor; box-shadow: 0 0 10px $lightColor; border-radius: 3px; }
105
104
  }
106
105
  &.edit-name .asset-name { display: block; }
@@ -115,10 +114,10 @@
115
114
  // GROUP ACTIONS
116
115
 
117
116
  .assets-group-actions {
118
- @include absolutePosition(0 0 0 0); background: $white;
119
- .accept { @include headerButton($positiveColor); float: right; margin-right: 1em; }
120
- .delete { @include headerButton($assertiveColor); float: right; margin-right: 1em; }
121
- .unselect { @include headerButton($stableColor); float: left; margin-left: 1em; }
117
+ @include position(absolute, 0 0 0 0); background: $white;
118
+ .accept { @include header-button($positiveColor); float: right; margin-right: 1em; }
119
+ .delete { @include header-button($assertiveColor); float: right; margin-right: 1em; }
120
+ .unselect { @include header-button($stableColor); float: left; margin-left: 1em; }
122
121
  }
123
122
 
124
123
  .assets-group-actions .accept { display: none; }
@@ -129,28 +128,24 @@
129
128
  // UPLOAD BUTTON
130
129
 
131
130
  .asset-upload {
132
- @include absolutePosition(0 -40px inherit inherit);
133
- @extend .icon-plus; @include noFocus;
131
+ @include position(absolute, 0 -40px null null);
132
+ @extend .icon-plus; @include no-focus-outline;
134
133
  cursor: pointer; padding-left: 80px;
135
134
  }
136
135
 
137
- .list header .asset-upload + .search { @include absolutePosition(0 40px inherit inherit); }
138
- .list.list-search header .asset-upload + .search { @include absolutePosition(0 0 inherit 0); }
139
- .module.assets.assets-uploading .list:not(:first-child) header .spinner { display: inline-block; }
136
+ .list header .asset-upload + .search { @include position(absolute, 0 40px null null); }
137
+ .list.list-search header .asset-upload + .search { @include position(absolute, 0 0 null 0); }
138
+ .loft.assets-uploading .list:not(:first-child) header .spinner { display: inline-block; }
140
139
 
141
140
 
142
141
  // MODAL MODE
143
142
 
144
- .module.assets {
145
- .modal-close {
146
- display: none;
147
- @include headerButton();
148
- @include absolutePosition(null null null 1em );
149
- }
143
+ .loft {
144
+ .modal-close { @include hide(); }
150
145
  &.module-modal {
151
- @include absolutePosition(.5em .5em 0em .5em); z-index: 1100;
146
+ @include position(absolute, 0 .5em 0 .5em); z-index: 1100;
152
147
 
153
- &:after { display: none; }
148
+ &:after { @include hide(); }
154
149
 
155
150
  // dark background
156
151
  &:before {
@@ -158,53 +153,53 @@
158
153
  content: ''; display: block; background: rgba(0,0,0,.25);
159
154
  }
160
155
 
161
- .modal-close { display: inline; }
156
+ .modal-close { @include header-button(); @include position(absolute, null null null 1em ); }
157
+ .header { top: 0; left: .5em; right: .5em; width: auto; }
158
+
162
159
  .list:first-child .back { display: none }
163
160
  }
164
161
  }
165
162
 
166
163
 
167
- /* TABLET LAYOUT */
168
-
169
- @media #{ $tablet } {
170
- .module.assets .list:not(:first-child) .items { font-size: 1em; }
171
-
172
- // ITEM
173
- .module.assets .list:not(:first-child) .items .item.asset {
164
+ /* Tablet ------------------------------------------------------------------ */
165
+ @media #{$tablet} {
166
+ // ITEMS
167
+ .loft .list:not(:first-child) .items { font-size: 1em; }
168
+ .loft .list:not(:first-child) .items .item.asset {
174
169
  padding-top: 19px; padding-bottom: 19px;
175
170
  .item-title {
176
171
  display: inline; cursor: pointer;
177
172
  &:hover { color: $positiveColor; text-decoration: underline; }
178
173
  }
179
- .item-subtitle { @include absolutePosition(1.55em 1em inherit inherit); }
174
+ .item-subtitle { @include position(absolute, 1.55em 1em null null); }
180
175
  .asset-name { top: 16px; }
181
176
  }
182
177
 
183
178
  // MODAL MODE
184
- .module.assets.module-modal { @include absolutePosition(1.5em 1.5em 0em 1.5em) }
179
+ .loft.module-modal { @include position(absolute, 1.5em 1.5em 0em 1.5em) }
180
+ .loft.module-modal .header { top: 0; left: 0; right: 0; width: auto; }
185
181
 
186
182
 
187
183
  // GRID MODE
188
184
  .assets-switch-mode {
189
- @include absolutePosition(inherit inherit inherit 1em);
190
- display: inline;
191
- font-size: .9em;
185
+ @include position(absolute, null null null 1em);
186
+ display: inline; font-size: .9em; line-height: 2.9; left: 3em;
192
187
  &:before { content: 'Grid'; color: $lightColor; margin-right: .25em; }
193
188
  &:after { content: 'List'; color: $stableColor; }
194
189
  }
195
- .module.assets.grid-mode .assets-switch-mode {
190
+ .loft.grid-mode .assets-switch-mode {
196
191
  &:before { color: $stableColor; }
197
192
  &:after { color: $lightColor; }
198
193
  }
199
194
 
200
- .module.assets.grid-mode {
195
+ .loft.grid-mode {
201
196
  .list:not(:first-child) .items {
202
197
  padding: .25em .25em 5em .75em;
203
198
  .item.asset { margin: 0 .75em 1.5em; float: left; display: inline-block; }
204
199
 
205
200
  .item.asset {
206
201
  padding-left: 1em; width: 222px; height: 222px;
207
- @include noBorder(); border: 1px solid $contrastColor; border-radius: 4px;
202
+ @include no-bottom-border; border: 1px solid $contrastColor; border-radius: 4px;
208
203
 
209
204
  // checkbox: position + decoration
210
205
  .asset-checkbox {
@@ -214,9 +209,9 @@
214
209
 
215
210
  // thumbnail
216
211
  .asset-icon {
217
- @include absolutePosition(10px inherit inherit 10px);
212
+ @include position(absolute, 10px null null 10px);
218
213
  width: 200px; height: 150px; background: $white; border-radius: 0;
219
- &:after { @include absolutePosition(0px 0px 0px 0px); box-shadow: 0 0 1px rgba(0,0,0,0.2) inset; content: ''; display: block; }
214
+ &:after { @include position(absolute, 0px 0px 0px 0px); box-shadow: 0 0 1px rgba(0,0,0,0.2) inset; content: ''; display: block; }
220
215
  }
221
216
 
222
217
  .asset-thumbnail-small { display: none; }
@@ -239,6 +234,15 @@
239
234
  }
240
235
 
241
236
 
237
+ /* Desktop ----------------------------------------------------------------- */
238
+ @media #{$desktop} {
239
+ // BACK
240
+ .loft .list:not(:first-child) .back { @include hide; }
241
+
242
+ // GRID MODE
243
+ .assets-switch-mode { left: 1em; }
244
+ }
245
+
242
246
 
243
247
 
244
248