satis 2.2.1 → 2.2.2
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.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/app/assets/config/satis_manifest.js +0 -1
- data/app/components/satis/card/component.css +8 -0
- data/app/components/satis/card/component.html.slim +20 -13
- data/app/components/satis/card/component.rb +49 -2
- data/app/components/satis/card/component_controller.js +78 -0
- data/app/components/satis/dropdown/component.html.slim +3 -3
- data/app/components/satis/dropdown/component.rb +31 -1
- data/app/components/satis/dropdown/component_controller.js +7 -5
- data/app/components/satis/sidebar/component.css +52 -74
- data/app/components/satis/sidebar_menu_item/component.css +94 -115
- data/app/components/satis/sidebar_menu_item/component_controller.js +113 -9
- data/app/javascript/satis/controllers/fields_for_controller.js +1 -1
- data/app/javascript/satis/controllers/index.js +3 -0
- data/app/javascript/satis/utility_controllers/show_hide_controller.js +1 -1
- data/lib/satis/version.rb +1 -1
- metadata +3 -5
- data/app/assets/fontawesome/brands.js +0 -6
- data/app/assets/fontawesome/fontawesome.js +0 -6
- data/app/assets/fontawesome/solid.js +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0a216f52695555dd93f0a81cd4bccbfd12a2a35e4c66d27ecb9b9d47a13230ab
|
|
4
|
+
data.tar.gz: 2c91093bfbdf423497d7be8cd3f369a7532576b2df54fcacd1819db96c1b24f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5e5993a3ddbad93c31e40f16020d5fa449414124c8eb2cdd8340d171798a36591d348bd58e431667771e085b7e7163e362840eeb566fa6e40b0fa2a7bd8562ad
|
|
7
|
+
data.tar.gz: faf38d6365356096841ac530334082d83bd1088190da0c1560800c174af553fc5ffe8591dfee14d2c3f81c35cd5cd96e10150c538fc44286bcb6030d2f2ebeb9
|
data/README.md
CHANGED
|
@@ -5,11 +5,15 @@ We use:
|
|
|
5
5
|
|
|
6
6
|
- [TailwindCSS](https://tailwindcss.com)
|
|
7
7
|
- [TailwindUI](https://tailwindui.com)
|
|
8
|
-
- [FontAwesome
|
|
8
|
+
- [FontAwesome 7](https://fontawesome.com/v7.0/)
|
|
9
9
|
- [ViewComponent](https://viewcomponent.org)
|
|
10
10
|
- [HotWired](https://hotwired.dev)
|
|
11
11
|
- [BEM](https://cssguidelin.es/#bem-like-naming)
|
|
12
12
|
|
|
13
|
+
## Upgrade
|
|
14
|
+
|
|
15
|
+
* From 2.3.0 onwards, we will no longer ship Fontawesome free. It conflicts with Fontawesome Pro. You can easily add the javascript files, you can download them from here: https://fontawesome.com/download. Use the files from the `js` folder. Put these in a folder which is in your manifest and it should just work.
|
|
16
|
+
|
|
13
17
|
## Installation
|
|
14
18
|
|
|
15
19
|
Your main app needs to have at least the following config/postcss.config.js:
|
|
@@ -5,6 +5,14 @@
|
|
|
5
5
|
@apply px-4 py-5 sm:px-6 dark:bg-gray-900 bg-white dark:border-gray-700 dark:text-gray-300;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
&__header--compact {
|
|
9
|
+
@apply px-3 py-3 sm:px-4;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&[data-satis-card-collapsible-value="true"] .sts-card__header {
|
|
13
|
+
@apply cursor-pointer select-none;
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
&__tabs {
|
|
9
17
|
@apply bg-white px-4 border-b border-gray-200 sm:px-5 bg-white dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300;
|
|
10
18
|
|
|
@@ -1,38 +1,45 @@
|
|
|
1
|
-
.sts-card data-controller="satis-tabs" data-satis-tabs-persist-value=persist data-satis-tabs-key-value=key id=identifier
|
|
1
|
+
.sts-card data-controller="satis-card satis-tabs" data-satis-tabs-persist-value=persist data-satis-tabs-key-value=key data-satis-card-collapsible-value=collapsible data-satis-card-collapsed-value=collapsed data-satis-card-identifier-value=identifier id=identifier
|
|
2
2
|
- if header?
|
|
3
|
-
.sts-card__header class="#{
|
|
3
|
+
.sts-card__header class=header_classes data-action="#{collapsible ? 'click->satis-card#toggle' : ''}"
|
|
4
4
|
.-ml-4.-mt-4.flex.justify-between.items-center.flex-wrap.sm:flex-nowrap
|
|
5
5
|
- if icon
|
|
6
6
|
.ml-4.mt-4.flex-shrink-0.text-primary-600.dark:text-gray-300
|
|
7
7
|
i class=icon
|
|
8
8
|
.ml-4.mt-4.flex-1
|
|
9
|
-
h3
|
|
9
|
+
h3 class=title_classes
|
|
10
10
|
= title
|
|
11
11
|
- if description.present?
|
|
12
12
|
p.mt-1.text-sm.text-gray-500.dark:text-gray-500
|
|
13
13
|
= description
|
|
14
14
|
|
|
15
15
|
- if actions.present? || initial_actions.present?
|
|
16
|
-
.ml-4.mt-4.flex-shrink-0
|
|
16
|
+
.ml-4.mt-4.flex-shrink-0 data-satis-card-target="actions"
|
|
17
17
|
.grid.grid-flow-row.gap-1.sm:grid-flow-col
|
|
18
18
|
- initial_actions.each do |action|
|
|
19
19
|
= action
|
|
20
20
|
- actions.each do |action|
|
|
21
21
|
= action
|
|
22
22
|
|
|
23
|
+
- if collapsible
|
|
24
|
+
.ml-4.mt-4.flex-shrink-0
|
|
25
|
+
button.text-gray-400.hover:text-gray-600.dark:hover:text-gray-200.transition-transform.duration-200 type="button" data-satis-card-target="collapseIcon"
|
|
26
|
+
i.fas.fa-chevron-down
|
|
27
|
+
|
|
23
28
|
- if menu
|
|
24
29
|
.ml-4.mt-2.flex-shrink-0
|
|
25
30
|
= render(Satis::Menu::Component.new(menu))
|
|
26
31
|
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
+
div data-satis-card-target="body"
|
|
33
|
+
- if tabs?
|
|
34
|
+
= render Satis::Tabs::Component.new(custom_link: custom_tabs_link).tap {|c| c.original_view_context = view_context } do |t|
|
|
35
|
+
- tabs.each_with_index do |ta, i|
|
|
36
|
+
- t.with_tab ta.name, id: ta.id, icon: ta.icon, padding: ta.padding, badge: ta.badge, menu: ta.menu, dirty: ta.dirty, title: ta.title, responsive: ta.responsive, selected_tab_index: ta.selected_tab_index do
|
|
37
|
+
= ta
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
- else
|
|
40
|
+
div class=content_classes style=content_style
|
|
41
|
+
= content
|
|
36
42
|
|
|
37
43
|
- if footer
|
|
38
|
-
=
|
|
44
|
+
div data-satis-card-target="footer"
|
|
45
|
+
= footer
|
|
@@ -7,7 +7,8 @@ module Satis
|
|
|
7
7
|
renders_many :tabs, Tab::Component
|
|
8
8
|
renders_one :footer
|
|
9
9
|
|
|
10
|
-
attr_reader :identifier, :icon, :description, :menu, :content_padding, :header_background_color, :initial_actions, :persist, :key
|
|
10
|
+
attr_reader :identifier, :icon, :description, :menu, :content_padding, :header_background_color, :initial_actions, :persist, :key,
|
|
11
|
+
:collapsible, :collapsed, :height, :min_height, :max_height, :padding, :compact
|
|
11
12
|
attr_writer :scope
|
|
12
13
|
|
|
13
14
|
def initialize(identifier = nil,
|
|
@@ -23,7 +24,14 @@ module Satis
|
|
|
23
24
|
scope: [],
|
|
24
25
|
actions: [],
|
|
25
26
|
key: nil,
|
|
26
|
-
persist: true
|
|
27
|
+
persist: true,
|
|
28
|
+
collapsible: false,
|
|
29
|
+
collapsed: false,
|
|
30
|
+
height: nil,
|
|
31
|
+
min_height: nil,
|
|
32
|
+
max_height: nil,
|
|
33
|
+
padding: nil,
|
|
34
|
+
compact: false)
|
|
27
35
|
super
|
|
28
36
|
|
|
29
37
|
if identifier.blank?
|
|
@@ -43,6 +51,13 @@ module Satis
|
|
|
43
51
|
@key = key
|
|
44
52
|
@custom_tabs_link = custom_tabs_link
|
|
45
53
|
@scope = scope.present? ? scope : identifier
|
|
54
|
+
@collapsible = collapsible
|
|
55
|
+
@collapsed = collapsed
|
|
56
|
+
@height = height
|
|
57
|
+
@min_height = min_height
|
|
58
|
+
@max_height = max_height
|
|
59
|
+
@padding = padding
|
|
60
|
+
@compact = compact
|
|
46
61
|
end
|
|
47
62
|
|
|
48
63
|
# def key
|
|
@@ -70,6 +85,38 @@ module Satis
|
|
|
70
85
|
def header?
|
|
71
86
|
icon.present? || title.present? || description.present? || menu
|
|
72
87
|
end
|
|
88
|
+
|
|
89
|
+
def content_style
|
|
90
|
+
styles = []
|
|
91
|
+
styles << "height: #{height}" if height
|
|
92
|
+
styles << "min-height: #{min_height}" if min_height
|
|
93
|
+
styles << "max-height: #{max_height}; overflow-y: auto" if max_height
|
|
94
|
+
styles.join('; ')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def content_classes
|
|
98
|
+
classes = []
|
|
99
|
+
if padding
|
|
100
|
+
classes << padding
|
|
101
|
+
elsif content_padding
|
|
102
|
+
classes << (compact ? 'px-4 py-3' : 'px-6 py-6')
|
|
103
|
+
end
|
|
104
|
+
classes.join(' ')
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def header_classes
|
|
108
|
+
base = tabs? ? '' : 'border-b border-gray-200'
|
|
109
|
+
base += ' sts-card__header--compact' if compact
|
|
110
|
+
base
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def title_classes
|
|
114
|
+
if compact
|
|
115
|
+
'text-sm leading-5 font-medium text-gray-900 dark:text-white'
|
|
116
|
+
else
|
|
117
|
+
'text-lg leading-6 font-medium text-gray-900 dark:text-white'
|
|
118
|
+
end
|
|
119
|
+
end
|
|
73
120
|
end
|
|
74
121
|
end
|
|
75
122
|
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["body", "collapseIcon", "actions", "footer"]
|
|
5
|
+
static values = {
|
|
6
|
+
collapsible: { type: Boolean, default: false },
|
|
7
|
+
collapsed: { type: Boolean, default: false },
|
|
8
|
+
identifier: String
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
connect() {
|
|
12
|
+
if (this.collapsibleValue) {
|
|
13
|
+
this._restoreState()
|
|
14
|
+
this._applyState(false)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
toggle(event) {
|
|
19
|
+
if (!this.collapsibleValue) return
|
|
20
|
+
|
|
21
|
+
// Don't toggle when clicking on actions, buttons, links, or menus inside the header
|
|
22
|
+
if (event.target.closest('a, button:not([data-satis-card-target="collapseIcon"]), .sts-menu, [data-action]')) {
|
|
23
|
+
if (!event.target.closest('[data-satis-card-target="collapseIcon"]')) return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.collapsedValue = !this.collapsedValue
|
|
27
|
+
this._applyState(true)
|
|
28
|
+
this._saveState()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_applyState(animate) {
|
|
32
|
+
const collapsed = this.collapsedValue
|
|
33
|
+
|
|
34
|
+
if (this.hasBodyTarget) {
|
|
35
|
+
if (animate) {
|
|
36
|
+
this.bodyTarget.style.transition = "max-height 0.2s ease-in-out, opacity 0.2s ease-in-out"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (collapsed) {
|
|
40
|
+
this.bodyTarget.style.maxHeight = "0px"
|
|
41
|
+
this.bodyTarget.style.opacity = "0"
|
|
42
|
+
this.bodyTarget.style.overflow = "hidden"
|
|
43
|
+
} else {
|
|
44
|
+
this.bodyTarget.style.maxHeight = ""
|
|
45
|
+
this.bodyTarget.style.opacity = ""
|
|
46
|
+
this.bodyTarget.style.overflow = ""
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (this.hasFooterTarget) {
|
|
51
|
+
this.footerTarget.style.display = collapsed ? "none" : ""
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Actions stay visible when collapsed — they're in the header
|
|
55
|
+
if (this.hasCollapseIconTarget) {
|
|
56
|
+
this.collapseIconTarget.style.transform = collapsed ? "rotate(-90deg)" : "rotate(0deg)"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
_storageKey() {
|
|
61
|
+
return `satis-card-${this.identifierValue}-collapsed`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_saveState() {
|
|
65
|
+
if (this.identifierValue) {
|
|
66
|
+
sessionStorage.setItem(this._storageKey(), this.collapsedValue)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
_restoreState() {
|
|
71
|
+
if (this.identifierValue) {
|
|
72
|
+
const stored = sessionStorage.getItem(this._storageKey())
|
|
73
|
+
if (stored !== null) {
|
|
74
|
+
this.collapsedValue = stored === "true"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -9,10 +9,10 @@ div.satis-dropdown data-action="keydown->satis-dropdown#dispatch" data-controlle
|
|
|
9
9
|
div.hidden.py-1 data-satis-dropdown-target="pills"
|
|
10
10
|
.flex.flex-col.items-center
|
|
11
11
|
.w-full.sts-dropdown class=input_class
|
|
12
|
-
|
|
12
|
+
div class=input_wrapper_classes
|
|
13
13
|
.flex.flex-auto.flex-wrap.sts-dropdown-input
|
|
14
14
|
/ Input where you can search
|
|
15
|
-
input
|
|
15
|
+
input class=search_input_classes data-action="input->satis-dropdown#search" data-satis-dropdown-target="searchInput" placeholder=placeholder autofocus=options[:autofocus]
|
|
16
16
|
div
|
|
17
17
|
/ Reset button
|
|
18
18
|
- unless @reset_button == false
|
|
@@ -28,7 +28,7 @@ div.satis-dropdown data-action="keydown->satis-dropdown#dispatch" data-controlle
|
|
|
28
28
|
template data-satis-dropdown-target="selectedItemsTemplate"
|
|
29
29
|
|
|
30
30
|
/ Container for results
|
|
31
|
-
|
|
31
|
+
div class=results_classes style=results_style data-satis-dropdown-target="results" data-action="scroll->satis-dropdown#scroll" tabindex="-1"
|
|
32
32
|
.flex.flex-col.w-full data-satis-dropdown-target="items"
|
|
33
33
|
- options[:collection]&.each do |item|
|
|
34
34
|
- data_attrs = item.try(:third) ? item.third : {}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Satis
|
|
4
4
|
module Dropdown
|
|
5
5
|
class Component < ViewComponent::Base
|
|
6
|
-
attr_reader :url, :form, :attribute, :title, :options
|
|
6
|
+
attr_reader :url, :form, :attribute, :title, :options, :dropdown_max_height, :dropdown_min_height, :dropdown_width, :dropdown_height, :compact
|
|
7
7
|
|
|
8
8
|
def initialize(form:, attribute:, **options, &block)
|
|
9
9
|
super
|
|
@@ -18,6 +18,11 @@ module Satis
|
|
|
18
18
|
@needs_exact_match = options[:needs_exact_match]
|
|
19
19
|
@reset_button = options[:reset_button] || options[:include_blank]
|
|
20
20
|
@toggle_button = options[:toggle_button] != false
|
|
21
|
+
@dropdown_max_height = options[:max_height]
|
|
22
|
+
@dropdown_min_height = options[:min_height]
|
|
23
|
+
@dropdown_width = options[:width]
|
|
24
|
+
@dropdown_height = options[:height]
|
|
25
|
+
@compact = options[:compact] || false
|
|
21
26
|
|
|
22
27
|
options[:input_html] ||= {}
|
|
23
28
|
|
|
@@ -113,6 +118,31 @@ module Satis
|
|
|
113
118
|
def input_class
|
|
114
119
|
[@options.fetch(:input_html, {}).fetch(:class, ""), form.has_error?(attribute) ? "is-invalid" : ""].join(" ")
|
|
115
120
|
end
|
|
121
|
+
|
|
122
|
+
def results_style
|
|
123
|
+
styles = []
|
|
124
|
+
styles << "max-height: #{dropdown_max_height}" if dropdown_max_height
|
|
125
|
+
styles << "min-height: #{dropdown_min_height}" if dropdown_min_height
|
|
126
|
+
styles << "width: #{dropdown_width}" if dropdown_width
|
|
127
|
+
styles << "height: #{dropdown_height}" if dropdown_height
|
|
128
|
+
styles.join('; ')
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def results_classes
|
|
132
|
+
classes = "hidden container sts-dropdown-results shadow dark:text-gray-300 z-10 rounded overflow-y-auto w-full"
|
|
133
|
+
classes += " max-h-select" unless dropdown_max_height
|
|
134
|
+
classes
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def input_wrapper_classes
|
|
138
|
+
compact ? 'h-9 p-1 flex rounded' : 'h-12 p-1 flex rounded'
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def search_input_classes
|
|
142
|
+
base = 'focus:ring-0 border-none p-1 px-2 appearance-none w-full sts-dropdown-input text-gray-800 dark:text-gray-300'
|
|
143
|
+
base += ' text-sm' if compact
|
|
144
|
+
base
|
|
145
|
+
end
|
|
116
146
|
end
|
|
117
147
|
end
|
|
118
148
|
end
|
|
@@ -355,6 +355,9 @@ export default class DropdownComponentController extends ApplicationController {
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
setHiddenSelect() {
|
|
358
|
+
if (this.element.querySelector('select[name*="[TEMPLATE]"]')) {
|
|
359
|
+
return
|
|
360
|
+
}
|
|
358
361
|
if (this.hiddenSelectTarget.options.length === 0) {
|
|
359
362
|
this.searchInputTarget.value = ""
|
|
360
363
|
this.pillsTarget.innerHTML = ""
|
|
@@ -542,7 +545,7 @@ export default class DropdownComponentController extends ApplicationController {
|
|
|
542
545
|
// auto select if there is only one match and we are not in freetext mode
|
|
543
546
|
if (!this.freeTextValue) {
|
|
544
547
|
if (matches.length === 1) {
|
|
545
|
-
if (this.filteredSearchQuery
|
|
548
|
+
if (this.filteredSearchQuery?.length >= this.minSearchQueryLengthValue &&
|
|
546
549
|
matches[0].getAttribute("data-satis-dropdown-item-text").toLowerCase().indexOf(this.lastSearch.toLowerCase()) >= 0) {
|
|
547
550
|
const dataDiv = matches[0].closest('[data-satis-dropdown-target="item"]')
|
|
548
551
|
this.selectItem(dataDiv)
|
|
@@ -601,15 +604,14 @@ export default class DropdownComponentController extends ApplicationController {
|
|
|
601
604
|
this.fetchResultsWith(ourUrl).then((itemCount) => {
|
|
602
605
|
if (this.hasResults) {
|
|
603
606
|
this.filterResultsChainTo()
|
|
604
|
-
|
|
605
|
-
if (!this.resultsShown && !this.chainToValue) {
|
|
607
|
+
if (!this.resultsShown) {
|
|
606
608
|
this.showResultsList()
|
|
607
609
|
}
|
|
608
610
|
|
|
609
611
|
// auto select when there is only 1 value
|
|
610
|
-
if (this.filteredSearchQuery
|
|
612
|
+
if (this.filteredSearchQuery?.length >= this.minSearchQueryLengthValue && this.nrOfItems === 1 && !this.freeTextValue) {
|
|
611
613
|
const dataDiv = this.itemTargets[0].closest('[data-satis-dropdown-target="item"]')
|
|
612
|
-
this.selectItem(dataDiv)
|
|
614
|
+
this.selectItem(dataDiv, true)
|
|
613
615
|
this.setSelectedItem(dataDiv.getAttribute("data-satis-dropdown-item-value"))
|
|
614
616
|
this.searchQueryValue = ""
|
|
615
617
|
} else if (this.searchQueryValue?.length > 0) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* ── Sidebar container ── */
|
|
1
2
|
.h-screen.flex .sidebar {
|
|
2
3
|
@apply dark:bg-gray-700 bg-white;
|
|
3
4
|
width: 260px;
|
|
@@ -6,77 +7,44 @@
|
|
|
6
7
|
left: 0;
|
|
7
8
|
margin-top: 4rem;
|
|
8
9
|
position: absolute;
|
|
9
|
-
overflow:
|
|
10
|
-
overflow-y:
|
|
10
|
+
overflow-x: hidden;
|
|
11
|
+
overflow-y: auto;
|
|
11
12
|
scrollbar-width: none;
|
|
12
13
|
z-index: 999;
|
|
13
|
-
transition:
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.h-screen.flex .sidebar.close .icon-link .sts-sidebar-menu-item{
|
|
18
|
-
z-index: 1100;
|
|
19
|
-
position: relative;
|
|
20
|
-
opacity: 0.99;
|
|
21
|
-
margin-left: 10px;
|
|
22
|
-
transition: backdrop-filter 0.3s ease-in-out, transform 0.3s ease-in-out;
|
|
14
|
+
transition: width 0.3s ease-in-out;
|
|
23
15
|
}
|
|
24
16
|
|
|
25
|
-
|
|
26
17
|
.h-screen.flex .sidebar.close {
|
|
27
|
-
position: absolute;
|
|
28
|
-
overflow: visible;
|
|
29
|
-
top: 0;
|
|
30
|
-
left: 0;
|
|
31
|
-
height: calc(100% - 4rem);
|
|
32
|
-
margin-top: 4rem;
|
|
33
18
|
width: 60px;
|
|
34
|
-
|
|
35
|
-
scrollbar-width: none;
|
|
19
|
+
overflow: visible;
|
|
36
20
|
}
|
|
37
21
|
|
|
38
22
|
.sidebar::-webkit-scrollbar {
|
|
39
23
|
display: none;
|
|
40
24
|
}
|
|
41
25
|
|
|
26
|
+
.dark .h-screen.flex .sidebar {
|
|
27
|
+
@apply bg-gray-800;
|
|
28
|
+
}
|
|
42
29
|
|
|
30
|
+
/* ── Topbar ── */
|
|
43
31
|
.h-screen.flex .topbar {
|
|
44
32
|
@apply bg-white dark:bg-gray-800;
|
|
45
33
|
height: 4rem;
|
|
46
34
|
display: flex;
|
|
47
35
|
max-width: 100%;
|
|
48
|
-
left:0;
|
|
49
|
-
margin-left: 0;
|
|
50
36
|
position: relative;
|
|
51
|
-
z-index:
|
|
52
|
-
transition: backdrop-filter 0.3s ease-in-out, transform 0.3s ease-in-out;
|
|
37
|
+
z-index: 1000;
|
|
53
38
|
}
|
|
54
39
|
|
|
40
|
+
/* ── Page body ── */
|
|
55
41
|
.page_body.close {
|
|
56
|
-
margin-left:
|
|
57
|
-
max-width:
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.h-screen.flex .sidebar .boxture-logo{
|
|
61
|
-
margin-top: 30px;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.sidebar.close .boxture-logo {
|
|
65
|
-
opacity: 0;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.h-screen.flex .sidebar.close .icon-link {
|
|
69
|
-
margin-top: 0;
|
|
70
|
-
transition: 0.3s ease;
|
|
71
|
-
transition-delay: 0.1s;
|
|
42
|
+
margin-left: 60px;
|
|
43
|
+
max-width: calc(100% - 60px);
|
|
72
44
|
}
|
|
73
45
|
|
|
74
|
-
|
|
75
|
-
.
|
|
76
|
-
margin-left: 2px;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.sidebar .boxture-logo {
|
|
46
|
+
/* ── Logo ── */
|
|
47
|
+
.h-screen.flex .sidebar .boxture-logo {
|
|
80
48
|
height: 52px;
|
|
81
49
|
width: 52px;
|
|
82
50
|
opacity: 0.5;
|
|
@@ -84,66 +52,76 @@
|
|
|
84
52
|
border-radius: 16px;
|
|
85
53
|
font-size: 30px;
|
|
86
54
|
color: #fff;
|
|
87
|
-
margin-top:
|
|
55
|
+
margin-top: 30px;
|
|
88
56
|
mix-blend-mode: multiply;
|
|
57
|
+
transition: opacity 0.3s ease-in-out;
|
|
89
58
|
}
|
|
90
59
|
|
|
91
60
|
.dark .sidebar .boxture-logo {
|
|
92
61
|
mix-blend-mode: normal;
|
|
93
62
|
}
|
|
94
63
|
|
|
95
|
-
.sidebar.close .
|
|
96
|
-
|
|
64
|
+
.sidebar.close .boxture-logo {
|
|
65
|
+
opacity: 0;
|
|
66
|
+
pointer-events: none;
|
|
97
67
|
}
|
|
98
68
|
|
|
99
|
-
.sidebar .
|
|
100
|
-
|
|
101
|
-
|
|
69
|
+
.sidebar .logo_name {
|
|
70
|
+
font-size: 10px;
|
|
71
|
+
opacity: 0.5;
|
|
72
|
+
text-align: center;
|
|
73
|
+
display: block;
|
|
102
74
|
}
|
|
103
75
|
|
|
104
|
-
.
|
|
105
|
-
|
|
76
|
+
.sidebar.close .logo_name {
|
|
77
|
+
display: none;
|
|
106
78
|
}
|
|
107
79
|
|
|
108
|
-
.dark .sidebar .
|
|
109
|
-
color: #
|
|
110
|
-
|
|
111
|
-
|
|
80
|
+
.dark .sidebar .logo_name {
|
|
81
|
+
color: #edecec;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.sidebar.close .profile-logo {
|
|
85
|
+
display: none;
|
|
112
86
|
}
|
|
113
87
|
|
|
88
|
+
/* ── Collapse arrow ── */
|
|
114
89
|
.h-screen.flex .sidebar .arrow {
|
|
115
90
|
margin-top: 20px;
|
|
116
91
|
font-size: 20px;
|
|
117
92
|
opacity: 0.5;
|
|
118
|
-
left: 0;
|
|
119
93
|
margin-left: 10px;
|
|
120
94
|
margin-right: 10px;
|
|
121
95
|
transform: scaleX(-1);
|
|
122
|
-
transition:
|
|
96
|
+
transition: transform 0.3s ease-in-out;
|
|
123
97
|
}
|
|
124
98
|
|
|
125
|
-
.h-screen.flex .sidebar.close .arrow{
|
|
99
|
+
.h-screen.flex .sidebar.close .arrow {
|
|
126
100
|
margin-left: 15px;
|
|
127
|
-
left: 0;
|
|
128
101
|
transform: scaleX(1);
|
|
129
102
|
}
|
|
130
103
|
|
|
131
|
-
.sidebar .
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
text-align: center;
|
|
135
|
-
display: block;
|
|
104
|
+
.sidebar .arrow:hover {
|
|
105
|
+
color: #555555;
|
|
106
|
+
cursor: pointer;
|
|
136
107
|
}
|
|
137
108
|
|
|
138
|
-
.sidebar
|
|
139
|
-
|
|
109
|
+
.dark .sidebar .arrow {
|
|
110
|
+
color: #ffffff;
|
|
111
|
+
opacity: 1;
|
|
112
|
+
margin-top: 20px;
|
|
140
113
|
}
|
|
141
114
|
|
|
142
|
-
.dark .
|
|
143
|
-
|
|
115
|
+
.dark .sidebar .arrow:hover {
|
|
116
|
+
color: #c0c0c0;
|
|
144
117
|
}
|
|
145
118
|
|
|
146
|
-
.
|
|
147
|
-
|
|
119
|
+
.h-screen.flex .sidebar.close .icon-link {
|
|
120
|
+
margin-top: 0;
|
|
121
|
+
transition: 0.3s ease;
|
|
122
|
+
transition-delay: 0.1s;
|
|
148
123
|
}
|
|
149
124
|
|
|
125
|
+
.sidebar.close .sts-sidebar-menu-item {
|
|
126
|
+
margin-left: 2px;
|
|
127
|
+
}
|