basefn 1.0.0

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 (154) hide show
  1. package/README.md +104 -0
  2. package/package.json +82 -0
  3. package/rescript.json +32 -0
  4. package/src/Basefn.css +14 -0
  5. package/src/Basefn.res +105 -0
  6. package/src/Basefn.res.mjs +114 -0
  7. package/src/Basefn__Dom.res +9 -0
  8. package/src/Basefn__Dom.res.mjs +24 -0
  9. package/src/Basefn__Utils.res +15 -0
  10. package/src/Basefn__Utils.res.mjs +32 -0
  11. package/src/Demo.res +1417 -0
  12. package/src/Demo.res.mjs +2328 -0
  13. package/src/Eita.res.mjs +105 -0
  14. package/src/Eita__Accordion.res.mjs +77 -0
  15. package/src/Eita__Alert.res.mjs +81 -0
  16. package/src/Eita__AppLayout.res.mjs +100 -0
  17. package/src/Eita__Avatar.res.mjs +40 -0
  18. package/src/Eita__Badge.res.mjs +65 -0
  19. package/src/Eita__Breadcrumb.res.mjs +53 -0
  20. package/src/Eita__Button.res.mjs +47 -0
  21. package/src/Eita__Card.res.mjs +60 -0
  22. package/src/Eita__Checkbox.res.mjs +36 -0
  23. package/src/Eita__Dom.res.mjs +16 -0
  24. package/src/Eita__Drawer.res.mjs +112 -0
  25. package/src/Eita__Dropdown.res.mjs +96 -0
  26. package/src/Eita__Grid.res.mjs +24 -0
  27. package/src/Eita__Input.res.mjs +54 -0
  28. package/src/Eita__Kbd.res.mjs +42 -0
  29. package/src/Eita__Label.res.mjs +24 -0
  30. package/src/Eita__Modal.res.mjs +93 -0
  31. package/src/Eita__Progress.res.mjs +101 -0
  32. package/src/Eita__Radio.res.mjs +38 -0
  33. package/src/Eita__Select.res.mjs +40 -0
  34. package/src/Eita__Separator.res.mjs +70 -0
  35. package/src/Eita__Sidebar.res.mjs +103 -0
  36. package/src/Eita__Slider.res.mjs +89 -0
  37. package/src/Eita__Spinner.res.mjs +69 -0
  38. package/src/Eita__Stepper.res.mjs +114 -0
  39. package/src/Eita__Switch.res.mjs +84 -0
  40. package/src/Eita__Tabs.res.mjs +57 -0
  41. package/src/Eita__Textarea.res.mjs +39 -0
  42. package/src/Eita__Timeline.res.mjs +86 -0
  43. package/src/Eita__Toast.res.mjs +112 -0
  44. package/src/Eita__Tooltip.res.mjs +60 -0
  45. package/src/Eita__Topbar.res.mjs +96 -0
  46. package/src/Eita__Typography.res.mjs +183 -0
  47. package/src/Eita__Utils.res.mjs +32 -0
  48. package/src/Example.res +111 -0
  49. package/src/Example.res.mjs +176 -0
  50. package/src/components/Basefn__Accordion.css +70 -0
  51. package/src/components/Basefn__Accordion.res +79 -0
  52. package/src/components/Basefn__Accordion.res.mjs +77 -0
  53. package/src/components/Basefn__Alert.css +79 -0
  54. package/src/components/Basefn__Alert.res +68 -0
  55. package/src/components/Basefn__Alert.res.mjs +78 -0
  56. package/src/components/Basefn__AppLayout.css +100 -0
  57. package/src/components/Basefn__AppLayout.res +74 -0
  58. package/src/components/Basefn__AppLayout.res.mjs +100 -0
  59. package/src/components/Basefn__Avatar.css +25 -0
  60. package/src/components/Basefn__Avatar.res +23 -0
  61. package/src/components/Basefn__Avatar.res.mjs +40 -0
  62. package/src/components/Basefn__Badge.css +71 -0
  63. package/src/components/Basefn__Badge.res +43 -0
  64. package/src/components/Basefn__Badge.res.mjs +65 -0
  65. package/src/components/Basefn__Breadcrumb.css +36 -0
  66. package/src/components/Basefn__Breadcrumb.res +45 -0
  67. package/src/components/Basefn__Breadcrumb.res.mjs +53 -0
  68. package/src/components/Basefn__Button.css +83 -0
  69. package/src/components/Basefn__Button.res +32 -0
  70. package/src/components/Basefn__Button.res.mjs +54 -0
  71. package/src/components/Basefn__Card.css +50 -0
  72. package/src/components/Basefn__Card.res +45 -0
  73. package/src/components/Basefn__Card.res.mjs +60 -0
  74. package/src/components/Basefn__Checkbox.css +72 -0
  75. package/src/components/Basefn__Checkbox.res +25 -0
  76. package/src/components/Basefn__Checkbox.res.mjs +36 -0
  77. package/src/components/Basefn__Drawer.css +168 -0
  78. package/src/components/Basefn__Drawer.res +86 -0
  79. package/src/components/Basefn__Drawer.res.mjs +112 -0
  80. package/src/components/Basefn__Dropdown.css +76 -0
  81. package/src/components/Basefn__Dropdown.res +85 -0
  82. package/src/components/Basefn__Dropdown.res.mjs +96 -0
  83. package/src/components/Basefn__Grid.css +11 -0
  84. package/src/components/Basefn__Grid.res +296 -0
  85. package/src/components/Basefn__Grid.res.mjs +263 -0
  86. package/src/components/Basefn__Icon.css +12 -0
  87. package/src/components/Basefn__Icon.res +196 -0
  88. package/src/components/Basefn__Icon.res.mjs +183 -0
  89. package/src/components/Basefn__Input.css +44 -0
  90. package/src/components/Basefn__Input.res +48 -0
  91. package/src/components/Basefn__Input.res.mjs +63 -0
  92. package/src/components/Basefn__Kbd.css +65 -0
  93. package/src/components/Basefn__Kbd.res +27 -0
  94. package/src/components/Basefn__Kbd.res.mjs +42 -0
  95. package/src/components/Basefn__Label.css +22 -0
  96. package/src/components/Basefn__Label.res +18 -0
  97. package/src/components/Basefn__Label.res.mjs +24 -0
  98. package/src/components/Basefn__Modal.css +100 -0
  99. package/src/components/Basefn__Modal.res +74 -0
  100. package/src/components/Basefn__Modal.res.mjs +93 -0
  101. package/src/components/Basefn__Progress.css +69 -0
  102. package/src/components/Basefn__Progress.res +88 -0
  103. package/src/components/Basefn__Progress.res.mjs +101 -0
  104. package/src/components/Basefn__Radio.css +72 -0
  105. package/src/components/Basefn__Radio.res +35 -0
  106. package/src/components/Basefn__Radio.res.mjs +38 -0
  107. package/src/components/Basefn__Select.css +44 -0
  108. package/src/components/Basefn__Select.res +33 -0
  109. package/src/components/Basefn__Select.res.mjs +40 -0
  110. package/src/components/Basefn__Separator.css +85 -0
  111. package/src/components/Basefn__Separator.res +45 -0
  112. package/src/components/Basefn__Separator.res.mjs +70 -0
  113. package/src/components/Basefn__Sidebar.css +141 -0
  114. package/src/components/Basefn__Sidebar.res +95 -0
  115. package/src/components/Basefn__Sidebar.res.mjs +107 -0
  116. package/src/components/Basefn__Slider.css +97 -0
  117. package/src/components/Basefn__Slider.res +68 -0
  118. package/src/components/Basefn__Slider.res.mjs +89 -0
  119. package/src/components/Basefn__Spinner.css +63 -0
  120. package/src/components/Basefn__Spinner.res +44 -0
  121. package/src/components/Basefn__Spinner.res.mjs +69 -0
  122. package/src/components/Basefn__Stepper.css +141 -0
  123. package/src/components/Basefn__Stepper.res +86 -0
  124. package/src/components/Basefn__Stepper.res.mjs +114 -0
  125. package/src/components/Basefn__Switch.css +80 -0
  126. package/src/components/Basefn__Switch.res +62 -0
  127. package/src/components/Basefn__Switch.res.mjs +84 -0
  128. package/src/components/Basefn__Tabs.css +54 -0
  129. package/src/components/Basefn__Tabs.res +73 -0
  130. package/src/components/Basefn__Tabs.res.mjs +57 -0
  131. package/src/components/Basefn__Textarea.css +41 -0
  132. package/src/components/Basefn__Textarea.res +28 -0
  133. package/src/components/Basefn__Textarea.res.mjs +41 -0
  134. package/src/components/Basefn__ThemeToggle.css +5 -0
  135. package/src/components/Basefn__ThemeToggle.res +29 -0
  136. package/src/components/Basefn__ThemeToggle.res.mjs +49 -0
  137. package/src/components/Basefn__Timeline.css +144 -0
  138. package/src/components/Basefn__Timeline.res +70 -0
  139. package/src/components/Basefn__Timeline.res.mjs +86 -0
  140. package/src/components/Basefn__Toast.css +100 -0
  141. package/src/components/Basefn__Toast.res +92 -0
  142. package/src/components/Basefn__Toast.res.mjs +112 -0
  143. package/src/components/Basefn__Tooltip.css +84 -0
  144. package/src/components/Basefn__Tooltip.res +42 -0
  145. package/src/components/Basefn__Tooltip.res.mjs +60 -0
  146. package/src/components/Basefn__Topbar.css +130 -0
  147. package/src/components/Basefn__Topbar.res +92 -0
  148. package/src/components/Basefn__Topbar.res.mjs +91 -0
  149. package/src/components/Basefn__Typography.css +120 -0
  150. package/src/components/Basefn__Typography.res +96 -0
  151. package/src/components/Basefn__Typography.res.mjs +175 -0
  152. package/src/styles/Basefn__Theme.res +63 -0
  153. package/src/styles/Basefn__Theme.res.mjs +65 -0
  154. package/src/styles/variables.css +199 -0
@@ -0,0 +1,38 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Xote from "xote/src/Xote.res.mjs";
4
+ import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
+
6
+ import './Basefn__Radio.css'
7
+ ;
8
+
9
+ function Basefn__Radio(props) {
10
+ let __disabled = props.disabled;
11
+ let disabled = __disabled !== undefined ? __disabled : false;
12
+ let base = "basefn-radio-wrapper";
13
+ return Xote__JSX.Elements.jsxs("label", {
14
+ class: disabled ? base + " basefn-radio-wrapper--disabled" : base,
15
+ children: Xote__JSX.array([
16
+ Xote__JSX.Elements.jsx("input", {
17
+ class: "basefn-radio-input",
18
+ type: "radio",
19
+ name: props.name,
20
+ value: props.value,
21
+ disabled: disabled,
22
+ checked: props.checked,
23
+ onChange: props.onChange
24
+ }),
25
+ Xote__JSX.Elements.jsx("span", {
26
+ class: "basefn-radio-label",
27
+ children: Xote.Component.text(props.label)
28
+ })
29
+ ])
30
+ });
31
+ }
32
+
33
+ let make = Basefn__Radio;
34
+
35
+ export {
36
+ make,
37
+ }
38
+ /* Not a pure module */
@@ -0,0 +1,44 @@
1
+ @import '../styles/variables.css';
2
+
3
+ .basefn-select {
4
+ display: block;
5
+ width: 100%;
6
+ font-family: var(--basefn-font-family);
7
+ font-size: var(--basefn-font-size-base);
8
+ font-weight: var(--basefn-font-weight-normal);
9
+ line-height: var(--basefn-line-height-normal);
10
+ height: var(--basefn-form-input-height);
11
+ padding: var(--basefn-form-input-padding-y) var(--basefn-form-input-padding-x);
12
+ padding-right: calc(var(--basefn-form-input-padding-x) * 2 + 1em);
13
+ background-color: var(--basefn-form-input-bg);
14
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
15
+ background-repeat: no-repeat;
16
+ background-position: right var(--basefn-form-input-padding-x) center;
17
+ background-size: 12px;
18
+ color: var(--basefn-form-input-text);
19
+ border: var(--basefn-border-width) solid var(--basefn-form-input-border);
20
+ border-radius: var(--basefn-radius-md);
21
+ outline: none;
22
+ appearance: none;
23
+ cursor: pointer;
24
+ transition: border-color var(--basefn-transition-fast), box-shadow var(--basefn-transition-fast);
25
+ }
26
+
27
+ .basefn-select:focus {
28
+ border-color: var(--basefn-form-input-border-focus);
29
+ box-shadow: 0 0 0 var(--basefn-focus-ring-width) var(--basefn-focus-ring-color);
30
+ }
31
+
32
+ .basefn-select:disabled {
33
+ background-color: var(--basefn-form-input-disabled-bg);
34
+ border-color: var(--basefn-form-input-disabled-border);
35
+ color: var(--basefn-form-input-disabled-text);
36
+ cursor: not-allowed;
37
+ opacity: 0.6;
38
+ }
39
+
40
+ .basefn-select option {
41
+ font-weight: var(--basefn-font-weight-normal);
42
+ color: var(--basefn-color-neutral-900);
43
+ background-color: white;
44
+ }
@@ -0,0 +1,33 @@
1
+ %%raw(`import './Basefn__Select.css'`)
2
+
3
+ open Xote
4
+
5
+ type selectOption = {
6
+ value: string,
7
+ label: string,
8
+ }
9
+
10
+ @jsx.component
11
+ let make = (
12
+ ~value: Signal.t<string>,
13
+ ~onChange: option<Dom.event => unit>=?,
14
+ ~options: Signal.t<array<selectOption>>,
15
+ ~disabled: bool=false,
16
+ ) => {
17
+ let onChange = (e: Dom.event) => {
18
+ let t = Obj.magic(e)["target"]
19
+ let v = t["value"]
20
+
21
+ Signal.set(value, v)
22
+
23
+ switch onChange {
24
+ | Some(onChange) => onChange(v)
25
+ | None => ()
26
+ }
27
+ }
28
+ <select name="test" class="basefn-select" value={value} disabled onChange>
29
+ {Component.list(options, opt =>
30
+ <option value={opt.value}> {Component.text(opt.label)} </option>
31
+ )}
32
+ </select>
33
+ }
@@ -0,0 +1,40 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Xote from "xote/src/Xote.res.mjs";
4
+ import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
+
6
+ import './Basefn__Select.css'
7
+ ;
8
+
9
+ function Basefn__Select(props) {
10
+ let __disabled = props.disabled;
11
+ let onChange = props.onChange;
12
+ let value = props.value;
13
+ let disabled = __disabled !== undefined ? __disabled : false;
14
+ let onChange$1 = e => {
15
+ let t = e.target;
16
+ let v = t.value;
17
+ Xote.Signal.set(value, v);
18
+ if (onChange !== undefined) {
19
+ return onChange(v);
20
+ }
21
+ };
22
+ return Xote__JSX.Elements.jsx("select", {
23
+ class: "basefn-select",
24
+ name: "test",
25
+ value: value,
26
+ disabled: disabled,
27
+ onChange: onChange$1,
28
+ children: Xote.Component.list(props.options, opt => Xote__JSX.Elements.jsx("option", {
29
+ value: opt.value,
30
+ children: Xote.Component.text(opt.label)
31
+ }))
32
+ });
33
+ }
34
+
35
+ let make = Basefn__Select;
36
+
37
+ export {
38
+ make,
39
+ }
40
+ /* Not a pure module */
@@ -0,0 +1,85 @@
1
+ @import "../styles/variables.css";
2
+
3
+ .basefn-separator {
4
+ border: 0;
5
+ }
6
+
7
+ /* Horizontal separator */
8
+ .basefn-separator--horizontal {
9
+ width: 100%;
10
+ height: 1px;
11
+ margin: 2rem 0;
12
+ }
13
+
14
+ /* Vertical separator */
15
+ .basefn-separator--vertical {
16
+ width: 1px;
17
+ height: 100%;
18
+ display: inline-block;
19
+ }
20
+
21
+ /* Variants */
22
+ .basefn-separator--solid {
23
+ background-color: var(--basefn-border-primary);
24
+ }
25
+
26
+ .basefn-separator--dashed {
27
+ background-image: linear-gradient(to right, var(--basefn-border-primary) 50%, transparent 50%);
28
+ background-size: 8px 1px;
29
+ background-repeat: repeat-x;
30
+ background-color: transparent;
31
+ }
32
+
33
+ .basefn-separator--vertical.basefn-separator--dashed {
34
+ background-image: linear-gradient(to bottom, var(--basefn-border-primary) 50%, transparent 50%);
35
+ background-size: 1px 8px;
36
+ background-repeat: repeat-y;
37
+ }
38
+
39
+ .basefn-separator--dotted {
40
+ background-image: linear-gradient(to right, var(--basefn-border-primary) 25%, transparent 25%);
41
+ background-size: 4px 1px;
42
+ background-repeat: repeat-x;
43
+ background-color: transparent;
44
+ }
45
+
46
+ .basefn-separator--vertical.basefn-separator--dotted {
47
+ background-image: linear-gradient(to bottom, var(--basefn-border-primary) 25%, transparent 25%);
48
+ background-size: 1px 4px;
49
+ background-repeat: repeat-y;
50
+ }
51
+
52
+ /* Separator with label */
53
+ .basefn-separator--with-label {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 1rem;
57
+ width: 100%;
58
+ background: transparent;
59
+ }
60
+
61
+ .basefn-separator__line {
62
+ flex: 1;
63
+ height: 1px;
64
+ background-color: var(--basefn-border-primary);
65
+ }
66
+
67
+ .basefn-separator--dashed .basefn-separator__line {
68
+ background-image: linear-gradient(to right, var(--basefn-border-primary) 50%, transparent 50%);
69
+ background-size: 8px 1px;
70
+ background-repeat: repeat-x;
71
+ background-color: transparent;
72
+ }
73
+
74
+ .basefn-separator--dotted .basefn-separator__line {
75
+ background-image: linear-gradient(to right, var(--basefn-border-primary) 25%, transparent 25%);
76
+ background-size: 4px 1px;
77
+ background-repeat: repeat-x;
78
+ background-color: transparent;
79
+ }
80
+
81
+ .basefn-separator__label {
82
+ font-size: 0.875rem;
83
+ color: #6b7280;
84
+ white-space: nowrap;
85
+ }
@@ -0,0 +1,45 @@
1
+ %%raw(`import './Basefn__Separator.css'`)
2
+
3
+ open Xote
4
+
5
+ type orientation = Horizontal | Vertical
6
+
7
+ type variant = Solid | Dashed | Dotted
8
+
9
+ let orientationToString = (orientation: orientation) => {
10
+ switch orientation {
11
+ | Horizontal => "horizontal"
12
+ | Vertical => "vertical"
13
+ }
14
+ }
15
+
16
+ let variantToString = (variant: variant) => {
17
+ switch variant {
18
+ | Solid => "solid"
19
+ | Dashed => "dashed"
20
+ | Dotted => "dotted"
21
+ }
22
+ }
23
+
24
+ @jsx.component
25
+ let make = (
26
+ ~orientation: orientation=Horizontal,
27
+ ~variant: variant=Solid,
28
+ ~label: option<string>=?,
29
+ ) => {
30
+ let getClassName = () => {
31
+ let orientationClass = "basefn-separator--" ++ orientationToString(orientation)
32
+ let variantClass = "basefn-separator--" ++ variantToString(variant)
33
+ "basefn-separator " ++ orientationClass ++ " " ++ variantClass
34
+ }
35
+
36
+ switch label {
37
+ | Some(text) =>
38
+ <div class={getClassName() ++ " basefn-separator--with-label"}>
39
+ <div class="basefn-separator__line" />
40
+ <span class="basefn-separator__label"> {Component.text(text)} </span>
41
+ <div class="basefn-separator__line" />
42
+ </div>
43
+ | None => <div class={getClassName()} role="separator" />
44
+ }
45
+ }
@@ -0,0 +1,70 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Xote from "xote/src/Xote.res.mjs";
4
+ import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
+
6
+ import './Basefn__Separator.css'
7
+ ;
8
+
9
+ function orientationToString(orientation) {
10
+ if (orientation === "Horizontal") {
11
+ return "horizontal";
12
+ } else {
13
+ return "vertical";
14
+ }
15
+ }
16
+
17
+ function variantToString(variant) {
18
+ switch (variant) {
19
+ case "Solid" :
20
+ return "solid";
21
+ case "Dashed" :
22
+ return "dashed";
23
+ case "Dotted" :
24
+ return "dotted";
25
+ }
26
+ }
27
+
28
+ function Basefn__Separator(props) {
29
+ let label = props.label;
30
+ let __variant = props.variant;
31
+ let __orientation = props.orientation;
32
+ let orientation = __orientation !== undefined ? __orientation : "Horizontal";
33
+ let variant = __variant !== undefined ? __variant : "Solid";
34
+ let getClassName = () => {
35
+ let orientationClass = "basefn-separator--" + orientationToString(orientation);
36
+ let variantClass = "basefn-separator--" + variantToString(variant);
37
+ return "basefn-separator " + orientationClass + " " + variantClass;
38
+ };
39
+ if (label !== undefined) {
40
+ return Xote__JSX.Elements.jsxs("div", {
41
+ class: getClassName() + " basefn-separator--with-label",
42
+ children: Xote__JSX.array([
43
+ Xote__JSX.Elements.jsx("div", {
44
+ class: "basefn-separator__line"
45
+ }),
46
+ Xote__JSX.Elements.jsx("span", {
47
+ class: "basefn-separator__label",
48
+ children: Xote.Component.text(label)
49
+ }),
50
+ Xote__JSX.Elements.jsx("div", {
51
+ class: "basefn-separator__line"
52
+ })
53
+ ])
54
+ });
55
+ } else {
56
+ return Xote__JSX.Elements.jsx("div", {
57
+ class: getClassName(),
58
+ role: "separator"
59
+ });
60
+ }
61
+ }
62
+
63
+ let make = Basefn__Separator;
64
+
65
+ export {
66
+ orientationToString,
67
+ variantToString,
68
+ make,
69
+ }
70
+ /* Not a pure module */
@@ -0,0 +1,141 @@
1
+ @import "../styles/variables.css";
2
+
3
+ .basefn-sidebar {
4
+ display: flex;
5
+ flex-direction: column;
6
+ background-color: var(--basefn-bg-primary);
7
+ color: var(--basefn-text-primary);
8
+ height: 100%;
9
+ overflow-y: auto;
10
+ border-right: 1px solid var(--basefn-border-primary);
11
+ }
12
+
13
+ .basefn-sidebar__header {
14
+ padding: 1rem 1.5rem;
15
+ flex-shrink: 0;
16
+ align-items: center;
17
+ height: 4rem;
18
+ display: flex;
19
+ border-bottom: 1px solid transparent;
20
+ border-bottom: 1px solid var(--basefn-border-primary);
21
+ }
22
+
23
+ .basefn-sidebar__logo {
24
+ font-size: 1.25rem;
25
+ font-weight: 700;
26
+ color: var(--basefn-text-primary);
27
+ font-family: var(--font-mono);
28
+ height: 100%;
29
+ display: flex;
30
+ align-items: center;
31
+ line-height: 2rem;
32
+ }
33
+
34
+ .basefn-sidebar__logo a {
35
+ text-decoration: none;
36
+ font-weight: 600;
37
+ height: 32px;
38
+ }
39
+
40
+ .basefn-sidebar__nav {
41
+ flex: 1;
42
+ overflow-y: auto;
43
+ padding: 1rem;
44
+ scrollbar-color: var(--basefn-color-neutral-300) transparent;
45
+ }
46
+
47
+ html[data-theme="dark"] .basefn-sidebar__nav {
48
+ scrollbar-color: var(--basefn-color-neutral-800) transparent;
49
+ }
50
+
51
+ .basefn-sidebar__section {
52
+ margin-bottom: 1.5rem;
53
+ }
54
+
55
+ .basefn-sidebar__section-title {
56
+ padding: 0.5rem 0.5rem;
57
+ font-size: var(--basefn-font-size-xs);
58
+ font-weight: 700;
59
+ text-transform: uppercase;
60
+ letter-spacing: 0.0625rem;
61
+ color: var(--basefn-text-tertiary);
62
+ }
63
+
64
+ .basefn-sidebar__section-title:empty {
65
+ display: none;
66
+ }
67
+
68
+ .basefn-sidebar__item {
69
+ display: flex;
70
+ align-items: center;
71
+ gap: 0.75rem;
72
+ padding: 0.5rem 1.25rem;
73
+ margin: 0 -0.5rem;
74
+ color: var(--basefn-text-tertiary);
75
+ font-weight: 300;
76
+ text-decoration: none;
77
+ cursor: pointer;
78
+ transition: all 0.2s;
79
+ border-radius: var(--basefn-radius-xl);
80
+ font-weight: 500;
81
+ margin-bottom: 0.25rem;
82
+ }
83
+
84
+ .basefn-sidebar__item:hover {
85
+ background-color: var(--basefn-bg-secondary-aa);
86
+ color: var(--basefn-text-primary);
87
+ }
88
+
89
+ .basefn-sidebar__item--active,
90
+ .basefn-sidebar__item--active:hover {
91
+ background-color: var(--basefn-bg-primary-aa);
92
+ color: var(--basefn-color-primary);
93
+ font-weight: 700;
94
+ }
95
+
96
+ .basefn-sidebar__item-icon {
97
+ width: 1.25rem;
98
+ height: 1.25rem;
99
+ flex-shrink: 0;
100
+ }
101
+
102
+ .basefn-sidebar__item-text {
103
+ font-size: 0.875rem;
104
+ }
105
+
106
+ .basefn-sidebar__footer {
107
+ padding: 1rem 1.5rem;
108
+ border-top: 1px solid var(--basefn-border-primary);
109
+ flex-shrink: 0;
110
+ }
111
+
112
+ /* Width variants */
113
+ .basefn-sidebar--sm {
114
+ width: 12rem;
115
+ }
116
+
117
+ .basefn-sidebar--md {
118
+ width: 16rem;
119
+ }
120
+
121
+ .basefn-sidebar--lg {
122
+ width: 20rem
123
+ }
124
+
125
+ /* Collapsible variant */
126
+ .basefn-sidebar--collapsed {
127
+ width: 64px;
128
+ display: none;
129
+ }
130
+
131
+ .basefn-sidebar--collapsed .basefn-sidebar__item-text,
132
+ .basefn-sidebar--collapsed .basefn-sidebar__section-title,
133
+ .basefn-sidebar--collapsed .basefn-sidebar__logo {
134
+ display: none;
135
+ }
136
+
137
+ .basefn-sidebar--collapsed .basefn-sidebar__item {
138
+ justify-content: center;
139
+ padding-left: 0;
140
+ padding-right: 0;
141
+ }
@@ -0,0 +1,95 @@
1
+ %%raw(`import './Basefn__Sidebar.css'`)
2
+
3
+ open Xote
4
+
5
+ type size = Sm | Md | Lg
6
+
7
+ type navItem = {
8
+ label: string,
9
+ icon: option<string>,
10
+ active: bool,
11
+ url: string,
12
+ }
13
+
14
+ type navSection = {
15
+ title: option<string>,
16
+ items: array<navItem>,
17
+ }
18
+
19
+ let sizeToString = (size: size) => {
20
+ switch size {
21
+ | Sm => "sm"
22
+ | Md => "md"
23
+ | Lg => "lg"
24
+ }
25
+ }
26
+
27
+ @jsx.component
28
+ let make = (
29
+ ~logo: option<Component.node>=?,
30
+ ~sections: array<navSection>,
31
+ ~footer: option<Component.node>=?,
32
+ ~size: size=Md,
33
+ ~collapsed: bool=false,
34
+ ) => {
35
+ let scrolling = Signal.make(false)
36
+ let getSidebarClass = () => {
37
+ let sizeClass = " basefn-sidebar--" ++ sizeToString(size)
38
+ let collapsedClass = collapsed ? " basefn-sidebar--collapsed" : ""
39
+ "basefn-sidebar" ++ sizeClass ++ collapsedClass
40
+ }
41
+
42
+ let _ = Effect.run(() => {
43
+ Basefn__Dom.addEventListener("scroll", () => {
44
+ let scrollY = %raw("window.scrollY")
45
+ Signal.set(scrolling, scrollY >= 64)
46
+ })
47
+ })
48
+
49
+ <div class={getSidebarClass()}>
50
+ {switch logo {
51
+ | Some(logoContent) => {
52
+ let class = Computed.make(() =>
53
+ "basefn-sidebar__header" ++ (
54
+ Signal.get(scrolling) ? " basefn-sidebar__header--scrolling" : ""
55
+ )
56
+ )
57
+ <div class>
58
+ <div class="basefn-sidebar__logo"> {logoContent} </div>
59
+ </div>
60
+ }
61
+ | None => <> </>
62
+ }}
63
+ <nav class="basefn-sidebar__nav">
64
+ {sections
65
+ ->Array.map(section => {
66
+ <div class="basefn-sidebar__section">
67
+ {switch section.title {
68
+ | Some(title) =>
69
+ <div class="basefn-sidebar__section-title"> {Component.text(title)} </div>
70
+ | None => <> </>
71
+ }}
72
+ {section.items
73
+ ->Array.mapWithIndex((item, index) => {
74
+ let itemClass =
75
+ "basefn-sidebar__item" ++ (item.active ? " basefn-sidebar__item--active" : "")
76
+
77
+ <Router.Link key={Int.toString(index)} class={itemClass} to={item.url}>
78
+ {switch item.icon {
79
+ | Some(icon) => <div class="basefn-sidebar__item-icon"> {Component.text(icon)} </div>
80
+ | None => <> </>
81
+ }}
82
+ <div class="basefn-sidebar__item-text"> {Component.text(item.label)} </div>
83
+ </Router.Link>
84
+ })
85
+ ->Component.fragment}
86
+ </div>
87
+ })
88
+ ->Component.fragment}
89
+ </nav>
90
+ {switch footer {
91
+ | Some(footerContent) => <div class="basefn-sidebar__footer"> {footerContent} </div>
92
+ | None => <> </>
93
+ }}
94
+ </div>
95
+ }
@@ -0,0 +1,107 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Xote from "xote/src/Xote.res.mjs";
4
+ import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
+ import * as Basefn__Dom from "../Basefn__Dom.res.mjs";
6
+ import * as Xote__Router from "xote/src/Xote__Router.res.mjs";
7
+
8
+ import './Basefn__Sidebar.css'
9
+ ;
10
+
11
+ function sizeToString(size) {
12
+ switch (size) {
13
+ case "Sm" :
14
+ return "sm";
15
+ case "Md" :
16
+ return "md";
17
+ case "Lg" :
18
+ return "lg";
19
+ }
20
+ }
21
+
22
+ function Basefn__Sidebar(props) {
23
+ let __collapsed = props.collapsed;
24
+ let __size = props.size;
25
+ let footer = props.footer;
26
+ let logo = props.logo;
27
+ let size = __size !== undefined ? __size : "Md";
28
+ let collapsed = __collapsed !== undefined ? __collapsed : false;
29
+ let scrolling = Xote.Signal.make(false, undefined, undefined);
30
+ let getSidebarClass = () => {
31
+ let sizeClass = " basefn-sidebar--" + sizeToString(size);
32
+ let collapsedClass = collapsed ? " basefn-sidebar--collapsed" : "";
33
+ return "basefn-sidebar" + sizeClass + collapsedClass;
34
+ };
35
+ Xote.Effect.run(() => Basefn__Dom.addEventListener("scroll", () => {
36
+ let scrollY = window.scrollY;
37
+ Xote.Signal.set(scrolling, scrollY >= 64);
38
+ }), undefined);
39
+ let tmp;
40
+ if (logo !== undefined) {
41
+ let $$class = Xote.Computed.make(() => "basefn-sidebar__header" + (
42
+ Xote.Signal.get(scrolling) ? " basefn-sidebar__header--scrolling" : ""
43
+ ), undefined);
44
+ tmp = Xote__JSX.Elements.jsx("div", {
45
+ class: $$class,
46
+ children: Xote__JSX.Elements.jsx("div", {
47
+ class: "basefn-sidebar__logo",
48
+ children: logo
49
+ })
50
+ });
51
+ } else {
52
+ tmp = Xote__JSX.jsx(Xote__JSX.jsxFragment, {});
53
+ }
54
+ return Xote__JSX.Elements.jsxs("div", {
55
+ class: getSidebarClass(),
56
+ children: Xote__JSX.array([
57
+ tmp,
58
+ Xote__JSX.Elements.jsx("nav", {
59
+ class: "basefn-sidebar__nav",
60
+ children: Xote.Component.fragment(props.sections.map(section => {
61
+ let title = section.title;
62
+ return Xote__JSX.Elements.jsxs("div", {
63
+ class: "basefn-sidebar__section",
64
+ children: Xote__JSX.array([
65
+ title !== undefined ? Xote__JSX.Elements.jsx("div", {
66
+ class: "basefn-sidebar__section-title",
67
+ children: Xote.Component.text(title)
68
+ }) : Xote__JSX.jsx(Xote__JSX.jsxFragment, {}),
69
+ Xote.Component.fragment(section.items.map((item, index) => {
70
+ let itemClass = "basefn-sidebar__item" + (
71
+ item.active ? " basefn-sidebar__item--active" : ""
72
+ );
73
+ let icon = item.icon;
74
+ return Xote__JSX.jsxsKeyed(Xote__Router.Link.make, {
75
+ to: item.url,
76
+ class: itemClass,
77
+ children: Xote__JSX.array([
78
+ icon !== undefined ? Xote__JSX.Elements.jsx("div", {
79
+ class: "basefn-sidebar__item-icon",
80
+ children: Xote.Component.text(icon)
81
+ }) : Xote__JSX.jsx(Xote__JSX.jsxFragment, {}),
82
+ Xote__JSX.Elements.jsx("div", {
83
+ class: "basefn-sidebar__item-text",
84
+ children: Xote.Component.text(item.label)
85
+ })
86
+ ])
87
+ }, index.toString(), undefined);
88
+ }))
89
+ ])
90
+ });
91
+ }))
92
+ }),
93
+ footer !== undefined ? Xote__JSX.Elements.jsx("div", {
94
+ class: "basefn-sidebar__footer",
95
+ children: footer
96
+ }) : Xote__JSX.jsx(Xote__JSX.jsxFragment, {})
97
+ ])
98
+ });
99
+ }
100
+
101
+ let make = Basefn__Sidebar;
102
+
103
+ export {
104
+ sizeToString,
105
+ make,
106
+ }
107
+ /* Not a pure module */