@kaspernj/api-maker 1.0.215 → 1.0.218

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.
Files changed (52) hide show
  1. package/package.json +5 -4
  2. package/src/base-model.mjs +1 -1
  3. package/src/bootstrap/attribute-row/basic-style.scss +9 -0
  4. package/src/bootstrap/attribute-row/index.jsx +84 -0
  5. package/src/bootstrap/attribute-rows.jsx +27 -0
  6. package/src/bootstrap/card.jsx +135 -0
  7. package/src/bootstrap/checkbox.jsx +79 -0
  8. package/src/bootstrap/checkboxes.jsx +122 -0
  9. package/src/bootstrap/index.js +0 -0
  10. package/src/bootstrap/input.jsx +160 -0
  11. package/src/bootstrap/invalid-feedback.jsx +31 -0
  12. package/src/bootstrap/live-table/model-row.jsx +150 -0
  13. package/src/bootstrap/live-table.jsx +399 -0
  14. package/src/bootstrap/paginate.jsx +153 -0
  15. package/src/bootstrap/radio-buttons.jsx +87 -0
  16. package/src/bootstrap/select.jsx +110 -0
  17. package/src/bootstrap/sort-link.jsx +102 -0
  18. package/src/collection-loader.jsx +7 -8
  19. package/src/inputs/auto-submit.mjs +37 -0
  20. package/src/inputs/checkbox.jsx +97 -0
  21. package/src/inputs/checkboxes.jsx +113 -0
  22. package/src/inputs/id-for-component.mjs +15 -0
  23. package/src/inputs/input-wrapper.jsx +170 -0
  24. package/src/inputs/input.jsx +235 -0
  25. package/src/inputs/money.jsx +177 -0
  26. package/src/inputs/name-for-component.mjs +15 -0
  27. package/src/inputs/select.jsx +87 -0
  28. package/src/model-class-require.mjs +1 -1
  29. package/src/model-name.mjs +6 -2
  30. package/src/params.mjs +7 -0
  31. package/src/super-admin/index-page/index.jsx +44 -0
  32. package/src/super-admin/index.jsx +46 -0
  33. package/src/super-admin/layout/header/index.jsx +60 -0
  34. package/src/super-admin/layout/header/style.scss +124 -0
  35. package/src/super-admin/layout/index.jsx +156 -0
  36. package/src/super-admin/layout/menu/index.jsx +116 -0
  37. package/src/super-admin/layout/menu/menu-content.jsx +55 -0
  38. package/src/super-admin/layout/menu/menu-item/index.jsx +27 -0
  39. package/src/super-admin/layout/menu/menu-item/style.scss +30 -0
  40. package/src/super-admin/layout/menu/style.scss +103 -0
  41. package/src/super-admin/layout/no-access.jsx +16 -0
  42. package/src/super-admin/layout/style.scss +25 -0
  43. package/src/super-admin/show-page.jsx +9 -0
  44. package/src/table/column-identifier.mjs +23 -0
  45. package/src/table/column-visible.mjs +7 -0
  46. package/src/table/model-row.jsx +182 -0
  47. package/src/table/select-calculator.mjs +48 -0
  48. package/src/table/style.scss +72 -0
  49. package/src/table/table-settings.js +175 -0
  50. package/src/table/table.jsx +498 -0
  51. package/src/table/variables.scss +11 -0
  52. package/src/table/with-breakpoint.jsx +48 -0
package/src/params.mjs CHANGED
@@ -15,6 +15,13 @@ export default class Params {
15
15
  return incorporator.merge()
16
16
  }
17
17
 
18
+ static withParams (params, opts = {}) {
19
+ const newParams = qs.stringify(params)
20
+ const newPath = `${location.pathname}?${newParams}`
21
+
22
+ return newPath
23
+ }
24
+
18
25
  static changeParams (given, opts = {}) {
19
26
  const params = Params.change(given)
20
27
  const newParams = qs.stringify(params)
@@ -0,0 +1,44 @@
1
+ import {digg, digs} from "diggerize"
2
+ import Params from "../../params"
3
+ import Table from "../../table/table"
4
+
5
+ export default class ApiMakerSuperAdminIndexPage extends React.PureComponent {
6
+ static propTypes = {
7
+ currentUser: PropTypes.object,
8
+ modelClass: PropTypes.func.isRequired,
9
+ queryParams: PropTypes.object.isRequired
10
+ }
11
+
12
+ render() {
13
+ const {currentUser, modelClass} = digs(this.props, "currentUser", "modelClass")
14
+
15
+ return (
16
+ <div>
17
+ <Table
18
+ columns={digg(this, "columns")}
19
+ currentUser={currentUser}
20
+ modelClass={modelClass}
21
+ viewModelPath={digg(this, "viewModelPath")}
22
+ />
23
+ </div>
24
+ )
25
+ }
26
+
27
+ columns = () => {
28
+ return [
29
+
30
+ ]
31
+ }
32
+
33
+ viewModelPath = (args) => {
34
+ const argName = digg(this.props.modelClass.modelClassData(), "camelizedLower")
35
+ const model = digg(args, argName)
36
+
37
+ console.log({args, model})
38
+
39
+ return Params.withParams({
40
+ model: this.props.modelClass.modelClassData().name,
41
+ model_id: model.primaryKey()
42
+ })
43
+ }
44
+ }
@@ -0,0 +1,46 @@
1
+ import {digs} from "diggerize"
2
+ import IndexPage from "./index-page"
3
+ import Layout from "./layout"
4
+ import * as modelsModule from "@kaspernj/api-maker/src/models.mjs.erb"
5
+ import ShowPage from "./show-page"
6
+ import withQueryParams from "on-location-changed/src/with-query-params"
7
+
8
+ class ApiMakerSuperAdmin extends React.PureComponent {
9
+ static propTypes = {
10
+ currentUser: PropTypes.object
11
+ }
12
+
13
+ render() {
14
+ const {currentUser} = this.props
15
+ const {queryParams} = digs(this.props, "queryParams")
16
+ const pageToShow = this.pageToShow()
17
+ let modelClass
18
+
19
+ if (queryParams.model) modelClass = modelsModule[queryParams.model]
20
+
21
+ return (
22
+ <Layout>
23
+ {pageToShow == "index" &&
24
+ <IndexPage currentUser={currentUser} modelClass={modelClass} queryParams={queryParams} />
25
+ }
26
+ {pageToShow == "show" &&
27
+ <ShowPage modelClass={modelClass} modelId={queryParams.modelId} />
28
+ }
29
+ </Layout>
30
+ )
31
+ }
32
+
33
+ pageToShow() {
34
+ const {queryParams} = digs(this.props, "queryParams")
35
+
36
+ if (queryParams.model && queryParams.model_id) {
37
+ return "show"
38
+ } else if (queryParams.model) {
39
+ return "index"
40
+ }
41
+
42
+ return "welcome"
43
+ }
44
+ }
45
+
46
+ export default withQueryParams(ApiMakerSuperAdmin)
@@ -0,0 +1,60 @@
1
+ import "./style"
2
+
3
+ export default class ApiMakerSuperAdminLayoutHeader extends BaseComponent {
4
+ static propTypes = PropTypesExact({
5
+ actions: PropTypes.node,
6
+ onTriggerMenu: PropTypes.func.isRequired,
7
+ title: PropTypes.string
8
+ })
9
+
10
+ headerActionsRef = React.createRef()
11
+ shape = new Shape(this, {headerActionsActive: false})
12
+
13
+ render() {
14
+ const {headerActionsRef} = digs(this, "headerActionsRef")
15
+ const {onGearsClicked} = digs(this, "onGearsClicked")
16
+ const {actions, onTriggerMenu, title} = this.props
17
+ const {headerActionsActive} = digs(this.shape, "headerActionsActive")
18
+
19
+ return (
20
+ <div className="components--admin--layout--header">
21
+ <EventListener event="mouseup" onCalled={digg(this, "onWindowMouseUp")} target={window} />
22
+ <div className="header-title-container">
23
+ {title}
24
+ </div>
25
+ {actions &&
26
+ <div className="header-actions-container" data-active={headerActionsActive}>
27
+ <div className="header-actions" ref={headerActionsRef}>
28
+ {actions}
29
+ </div>
30
+ </div>
31
+ }
32
+ <div className="burger-menu-container">
33
+ {actions &&
34
+ <a className="actions-link" href="#" onClick={onGearsClicked}>
35
+ <i className="fa fa-gear" />
36
+ </a>
37
+ }
38
+ <a className="burger-menu-link" href="#" onClick={onTriggerMenu}>
39
+ <i className="fa fa-bars" />
40
+ </a>
41
+ </div>
42
+ </div>
43
+ )
44
+ }
45
+
46
+ onGearsClicked = (e) => {
47
+ e.preventDefault()
48
+ this.shape.set({
49
+ headerActionsActive: !this.shape.headerActionsActive
50
+ })
51
+ }
52
+
53
+ onWindowMouseUp = (e) => {
54
+ const {headerActionsRef} = digs(this, "headerActionsRef")
55
+ const {headerActionsActive} = digs(this.shape, "headerActionsActive")
56
+
57
+ // Close the header actions menu if clicked happened outside
58
+ if (headerActionsActive && headerActionsRef.current && !headerActionsRef.current.contains(e.target)) this.shape.set({headerActionsActive: false})
59
+ }
60
+ }
@@ -0,0 +1,124 @@
1
+ @import "stylesheets/variables";
2
+
3
+ .components--admin--layout--header {
4
+ top: 0;
5
+ display: flex;
6
+ height: 100px;
7
+ align-items: center;
8
+ padding-right: 30px;
9
+ padding-left: 30px;
10
+ background: #fff;
11
+ color: #282a33;
12
+
13
+ @media (max-width: $sm-to) {
14
+ position: absolute;
15
+ width: 100%;
16
+
17
+ .header-actions-container {
18
+ position: fixed;
19
+ top: 0;
20
+ left: 0;
21
+
22
+ display: flex;
23
+ width: 100vw;
24
+ height: 100vh;
25
+ align-items: center;
26
+ justify-content: center;
27
+
28
+ background: rgba(#000, .8);
29
+
30
+ &[data-active="false"] {
31
+ display: none;
32
+ }
33
+ }
34
+
35
+ .header-actions {
36
+ min-width: 80vw;
37
+ max-width: 100vw;
38
+ background: #fff;
39
+
40
+ .action-button {
41
+ display: block;
42
+ padding: 11px;
43
+
44
+ .fa {
45
+ margin-right: 5px;
46
+ }
47
+
48
+ + .action-button {
49
+ border-top: 1px solid #c9c9c9;
50
+ }
51
+
52
+ &:link,
53
+ &:visited {
54
+ color: #000;
55
+ }
56
+
57
+ &:active,
58
+ &:hover {
59
+ background: #dddcf0;
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ @media (min-width: $md-from) {
66
+ position: fixed;
67
+ left: 250px;
68
+ width: calc(100% - 250px);
69
+
70
+ .header-actions-container {
71
+ margin-left: auto;
72
+ }
73
+
74
+ .header-actions {
75
+ .action-button {
76
+ display: inline-block;
77
+ padding: 7px 10px;
78
+ border: 1px solid #cbd5e1;
79
+ margin-right: 4px;
80
+ margin-bottom: 4px;
81
+ border-radius: 5px;
82
+ font-size: 13px;
83
+
84
+ &:link,
85
+ &:visited {
86
+ color: #000;
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ @media (min-width: $lg-from) {
93
+ left: 290px;
94
+ width: calc(100% - 290px);
95
+ }
96
+
97
+ .burger-menu-container {
98
+ @media (max-width: $sm-to) {
99
+ margin-left: auto;
100
+ font-size: 28px;
101
+ }
102
+
103
+ @media (min-width: $md-from) {
104
+ display: none;
105
+ }
106
+ }
107
+
108
+ .actions-link {
109
+ margin-right: 8px;
110
+ font-size: 22px;
111
+ }
112
+
113
+ .actions-link,
114
+ .burger-menu-link {
115
+ &:link,
116
+ &:visited {
117
+ color: #1b1c1e;
118
+ }
119
+ }
120
+
121
+ .header-title-container {
122
+ font-size: 22px;
123
+ }
124
+ }
@@ -0,0 +1,156 @@
1
+ import "./style"
2
+ import CommandsPool from "@kaspernj/api-maker/src/commands-pool"
3
+ import Header from "./header"
4
+ import Menu from "./menu"
5
+
6
+ const UsersSignIn = React.lazy(() => import("components/users/sign-in"))
7
+ const NoAccess = React.lazy(() => import("./no-access"))
8
+
9
+ class ApiMakerSuperAdminLayout extends React.PureComponent {
10
+ static defaultProps = {
11
+ requireAdmin: true
12
+ }
13
+
14
+ static propTypes = PropTypesExact({
15
+ actions: PropTypes.node,
16
+ active: PropTypes.string,
17
+ children: PropTypes.node,
18
+ className: PropTypes.string,
19
+ currentCustomer: PropTypes.instanceOf(User),
20
+ currentCustomerId: PropTypes.string,
21
+ currentUser: PropTypes.instanceOf(User),
22
+ headTitle: PropTypes.string,
23
+ headerTitle: PropTypes.string,
24
+ requireAdmin: PropTypes.bool.isRequired
25
+ })
26
+
27
+ componentDidMount() {
28
+ CommandsPool.current().globalRequestData.layout = "admin"
29
+ CommandsPool.current().globalRequestData.locale = I18n.locale
30
+
31
+ this.setDocumentTitle()
32
+ }
33
+
34
+ componentDidUpdate() {
35
+ this.setDocumentTitle()
36
+ }
37
+
38
+ setDocumentTitle() {
39
+ const headTitle = this.props.headTitle || this.props.headerTitle
40
+
41
+ if (headTitle) {
42
+ document.title = headTitle
43
+ } else {
44
+ document.title = "Wooftech"
45
+ }
46
+ }
47
+
48
+ shape = new Shape(this, {
49
+ menuTriggered: false
50
+ })
51
+
52
+ render() {
53
+ const {
54
+ actions,
55
+ active,
56
+ children,
57
+ className,
58
+ currentCustomer,
59
+ currentCustomerId,
60
+ currentUser,
61
+ headerTitle,
62
+ menu,
63
+ requireAdmin,
64
+ ...restProps
65
+ } = this.props
66
+ const {menuTriggered} = digs(this.shape, "menuTriggered")
67
+ const noAccess = this.noAccess()
68
+
69
+ return (
70
+ <div className={classNames("components--admin--layout", className)} data-menu-triggered={menuTriggered} {...restProps}>
71
+ <Menu
72
+ active={active}
73
+ noAccess={noAccess}
74
+ onRequestMenuClose={digg(this, "onRequestMenuClose")}
75
+ triggered={menuTriggered}
76
+ />
77
+ <Header actions={actions} onTriggerMenu={digg(this, "onTriggerMenu")} title={headerTitle} />
78
+ <div className="app-layout-content-container">
79
+ {noAccess &&
80
+ <>
81
+ <NoAccess />
82
+ {currentUser &&
83
+ <>
84
+ <div className="mb-4">
85
+ {I18n.t("js.components.app_layout.try_signing_out_and_in_with_a_different_user")}
86
+ </div>
87
+ {(isCurrentUserA("teacher") || isCurrentUserA("student")) &&
88
+ <div className="mb-4">
89
+ {this.clickHereToAccessTheUserUniverse()}
90
+ </div>
91
+ }
92
+ </>
93
+ }
94
+ {!currentUser &&
95
+ <>
96
+ <div className="mb-4">
97
+ {I18n.t("js.components.app_layout.try_signing_in")}
98
+ </div>
99
+ <UsersSignIn />
100
+ </>
101
+ }
102
+ </>
103
+ }
104
+ {!noAccess && children}
105
+ </div>
106
+ </div>
107
+ )
108
+ }
109
+
110
+ clickHereToAccessTheUserUniverse() {
111
+ const replaces = [
112
+ {
113
+ component: (
114
+ <Link key="here-user-universe-link" to={Routes.userRootPath()}>
115
+ {I18n.t("js.components.app_layout.here")}
116
+ </Link>
117
+ ),
118
+ text: "%{here}"
119
+ },
120
+ {
121
+ component: (
122
+ <Link key="user-universe-link" to={Routes.userRootPath()}>
123
+ {I18n.t("js.components.app_layout.user_universe")}
124
+ </Link>
125
+ ),
126
+ text: "%{user_universe}"
127
+ }
128
+ ]
129
+
130
+ return (
131
+ <TextComponentReplace
132
+ replaces={replaces}
133
+ text={I18n.t("js.components.app_layout.click_here_to_access_the_user_universe")}
134
+ />
135
+ )
136
+ }
137
+
138
+ onRequestMenuClose = () => this.shape.set({menuTriggered: false})
139
+
140
+ onTriggerMenu = (e) => {
141
+ e.preventDefault()
142
+
143
+ this.shape.set({menuTriggered: !this.shape.menuTriggered})
144
+ }
145
+
146
+ noAccess() {
147
+ const {currentUser, requireAdmin} = digs(this.props, "currentUser", "requireAdmin")
148
+
149
+ if (requireAdmin && currentUser && !isCurrentUserA("admin") && !isCurrentUserA("hacker")) return true
150
+ if (requireAdmin && !currentUser) return true
151
+
152
+ return false
153
+ }
154
+ }
155
+
156
+ export default withCurrentUser(ApiMakerSuperAdminLayout)
@@ -0,0 +1,116 @@
1
+ import "./style"
2
+ import {PopupMenu, PopupMenuItem} from "components/popup-menu"
3
+ import MenuContent from "./menu-content"
4
+ import MenuItem from "./menu-item"
5
+
6
+ class ComponentsAdminLayoutMenu extends BaseComponent {
7
+ static propTypes = PropTypesExact({
8
+ active: PropTypes.string,
9
+ currentUser: PropTypes.instanceOf(User),
10
+ noAccess: PropTypes.bool.isRequired,
11
+ onRequestMenuClose: PropTypes.func.isRequired,
12
+ triggered: PropTypes.bool.isRequired
13
+ })
14
+
15
+ menuUserItemsRef = React.createRef()
16
+ rootRef = React.createRef()
17
+ shape = new Shape(this, {userMenuItemOpen: false})
18
+
19
+ render() {
20
+ const {menuUserItemsRef, onUserItemsClicked, rootRef} = digs(this, "menuUserItemsRef", "onUserItemsClicked", "rootRef")
21
+ const {active} = this.props
22
+ const {
23
+ currentUser,
24
+ noAccess,
25
+ triggered
26
+ } = digs(
27
+ this.props,
28
+ "currentUser",
29
+ "noAccess",
30
+ "triggered"
31
+ )
32
+ const {userMenuItemOpen} = digs(this.shape, "userMenuItemOpen")
33
+
34
+ return (
35
+ <div className="components--admin--layout--menu" data-triggered={triggered} ref={rootRef}>
36
+ <EventListener event="mouseup" onCalled={digg(this, "onWindowMouseUp")} target={window} />
37
+ <div className="menu-logo">
38
+ <Link className="menu-logo-link" to={Routes.adminRootPath()}>
39
+ Admin
40
+ </Link>
41
+ </div>
42
+ <div className="menu-items-center">
43
+ {!noAccess &&
44
+ <MenuContent active={active} />
45
+ }
46
+ </div>
47
+ <div className="menu-items-bottom">
48
+ {currentUser &&
49
+ <div className="menu-user-section">
50
+ <div className="menu-user-icon">
51
+ <i className="fa fa-user" />
52
+ </div>
53
+ <div className="menu-user-name">
54
+ <div className="menu-user-name-container">
55
+ {currentUser.name()}
56
+ </div>
57
+ </div>
58
+ <div className="menu-user-items" ref={menuUserItemsRef}>
59
+ {userMenuItemOpen &&
60
+ <PopupMenu>
61
+ <PopupMenuItem
62
+ children={I18n.t("js.components.app_layout.menu.notification_settings")}
63
+ className="notifications-settings-menu-item"
64
+ to="#"
65
+ />
66
+ </PopupMenu>
67
+ }
68
+ <a className="menu-user-items-link" href="#" onClick={onUserItemsClicked}>
69
+ <i className="fa fa-ellipsis" />
70
+ </a>
71
+ </div>
72
+ </div>
73
+ }
74
+ {currentUser &&
75
+ <MenuItem
76
+ active
77
+ className="sign-out-menu-item"
78
+ icon="sign-out-alt"
79
+ label={I18n.t("js.components.admin.layout.menu.sign_out")}
80
+ onClick={digg(this, "onSignOutClicked")}
81
+ />
82
+ }
83
+ </div>
84
+ </div>
85
+ )
86
+ }
87
+
88
+ onSignOutClicked = async (e) => {
89
+ e.preventDefault()
90
+
91
+ try {
92
+ await Devise.signOut()
93
+ FlashMessage.success(I18n.t("js.components.admin.layout.menu.you_have_been_signed_out"))
94
+ } catch (error) {
95
+ FlashMessage.errorResponse(error)
96
+ }
97
+ }
98
+
99
+ onUserItemsClicked = (e) => {
100
+ e.preventDefault()
101
+ this.shape.set({userMenuItemOpen: !this.shape.userMenuItemOpen})
102
+ }
103
+
104
+ onWindowMouseUp = (e) => {
105
+ const {menuUserItemsRef, rootRef} = digs(this, "menuUserItemsRef", "rootRef")
106
+ const {triggered} = digs(this.props, "triggered")
107
+
108
+ // Close the menu if triggered (menu is open on mobile)
109
+ if (triggered && !rootRef.current.contains(e.target)) setTimeout(this.props.onRequestMenuClose)
110
+
111
+ // Close the user items menu if clicked happened outside of that
112
+ if (!menuUserItemsRef?.current?.contains(e.target)) this.shape.set({userMenuItemOpen: false})
113
+ }
114
+ }
115
+
116
+ export default withCurrentUser(ComponentsAdminLayoutMenu)
@@ -0,0 +1,55 @@
1
+ import CanCanLoader from "@kaspernj/api-maker/src/can-can-loader"
2
+ import MenuItem from "components/admin/layout/menu/menu-item"
3
+ import Params from "../../../params"
4
+ import * as modelsModule from "@kaspernj/api-maker/src/models.mjs.erb"
5
+
6
+ const models = []
7
+
8
+ for (const modelKey of Object.keys(modelsModule)) {
9
+ const model = modelsModule[modelKey]
10
+
11
+ models.push(model)
12
+ }
13
+
14
+ const abilities = []
15
+
16
+ for (const model of models) {
17
+ abilities.push(
18
+ [model, ["index"]]
19
+ )
20
+ }
21
+
22
+ export default class ComponentsAdminLayoutMenuContent extends BaseComponent {
23
+ static propTypes = PropTypesExact({
24
+ active: PropTypes.string
25
+ })
26
+
27
+ shape = new Shape(this, {
28
+ canCan: undefined
29
+ })
30
+
31
+ render() {
32
+ const {active} = digs(this.props, "active")
33
+ const {canCan} = digs(this.shape, "canCan")
34
+
35
+ return (
36
+ <>
37
+ <CanCanLoader abilities={abilities} component={this} />
38
+ {this.sortedModels().map((model) => canCan?.can("index", model) &&
39
+ <MenuItem
40
+ active={active}
41
+ icon="sitemap"
42
+ identifier="check-ins"
43
+ label={model.modelName().human({count: 2})}
44
+ key={model.modelClassData().name}
45
+ to={Params.withParams({model: model.modelClassData().name})}
46
+ />
47
+ )}
48
+ </>
49
+ )
50
+ }
51
+
52
+ sortedModels() {
53
+ return models.sort((a, b) => a.modelName().human({count: 2}).toLowerCase().localeCompare(b.modelName().human({count: 2}).toLowerCase()))
54
+ }
55
+ }
@@ -0,0 +1,27 @@
1
+ import "./style"
2
+
3
+ export default class ComponentsAdminLayoutMenuMenuItem extends BaseComponent {
4
+ static propTypes = {
5
+ active: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
6
+ className: PropTypes.string,
7
+ icon: PropTypes.string.isRequired,
8
+ label: PropTypes.node
9
+ }
10
+
11
+ render() {
12
+ const {active, children, className, icon, identifier, label, to, ...restProps} = this.props
13
+
14
+ return (
15
+ <Link
16
+ className={classNames("components--admin--layout--menu--menu-item", className)}
17
+ data-active={active === true || active == identifier}
18
+ data-identifier={identifier}
19
+ to={to || "#"}
20
+ {...restProps}
21
+ >
22
+ <i className={`fa fa-fw fa-${icon} menu-item-icon`} />
23
+ {children || label}
24
+ </Link>
25
+ )
26
+ }
27
+ }
@@ -0,0 +1,30 @@
1
+ .components--admin--layout--menu--menu-item {
2
+ display: flex;
3
+ width: 80%;
4
+ align-items: center;
5
+ padding: 10px 14px;
6
+ margin-right: auto;
7
+ margin-left: auto;
8
+ text-decoration: none;
9
+
10
+ &:link,
11
+ &:visited {
12
+ color: #6f6f71;
13
+ }
14
+
15
+ &[data-active="true"],
16
+ &:hover {
17
+ background: #323435;
18
+ border-radius: 7px;
19
+ color: #b9b9bb;
20
+ }
21
+
22
+ .menu-item-icon {
23
+ margin-right: 4px;
24
+ font-size: 12px;
25
+ }
26
+
27
+ + .components--admin--layout--menu--menu-item {
28
+ margin-top: 6px;
29
+ }
30
+ }