basefn 1.1.6 → 1.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basefn",
3
- "version": "1.1.6",
3
+ "version": "1.3.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/brnrdog/basefn.git"
@@ -81,6 +81,6 @@
81
81
  "@semantic-release/npm": "^13.1.3",
82
82
  "rescript": "^12.0.1",
83
83
  "vite": "^5.0.0",
84
- "xote": "^4.10.0"
84
+ "xote": "^4.11.0"
85
85
  }
86
86
  }
package/src/Basefn.res CHANGED
@@ -41,6 +41,7 @@ type sidebarNavSection = Basefn__Sidebar.navSection
41
41
  type topbarSize = Basefn__Topbar.size
42
42
  type topbarNavItem = Basefn__Topbar.navItem
43
43
  type appLayoutContentWidth = Basefn__AppLayout.contentWidth
44
+ type appLayoutTopbarPosition = Basefn__AppLayout.topbarPosition
44
45
  type iconName = Basefn__Icon.name
45
46
  type iconSize = Basefn__Icon.size
46
47
  type gridColumns = Basefn__Grid.columns
@@ -29,4 +29,4 @@ export {
29
29
  makeReactive,
30
30
  makeReactiveFromSignal,
31
31
  }
32
- /* Signals Not a pure module */
32
+ /* No side effect */
@@ -4,6 +4,23 @@
4
4
  width: 100%;
5
5
  }
6
6
 
7
+ .basefn-app-layout__body {
8
+ display: flex;
9
+ flex: 1;
10
+ min-height: 100vh;
11
+ width: 100%;
12
+ }
13
+
14
+ /* When topbar is above, adjust layout direction */
15
+ .basefn-app-layout--topbar-above {
16
+ flex-direction: column;
17
+ }
18
+
19
+ .basefn-app-layout--topbar-above .basefn-app-layout__body {
20
+ flex: 1;
21
+ min-height: 0;
22
+ }
23
+
7
24
  .basefn-app-layout__sidebar {
8
25
  position: fixed;
9
26
  left: 0;
@@ -12,6 +29,19 @@
12
29
  z-index: 200;
13
30
  }
14
31
 
32
+ /* When topbar is above, sidebar starts below topbar */
33
+ .basefn-app-layout--topbar-above .basefn-app-layout__sidebar {
34
+ top: 64px; /* Default topbar height (md) */
35
+ }
36
+
37
+ .basefn-app-layout--topbar-above.basefn-app-layout--topbar-sm .basefn-app-layout__sidebar {
38
+ top: 56px;
39
+ }
40
+
41
+ .basefn-app-layout--topbar-above.basefn-app-layout--topbar-lg .basefn-app-layout__sidebar {
42
+ top: 72px;
43
+ }
44
+
15
45
  .basefn-app-layout__main-wrapper {
16
46
  flex: 1;
17
47
  display: flex;
@@ -43,6 +73,14 @@
43
73
  z-index: 100;
44
74
  }
45
75
 
76
+ /* When topbar is above all content */
77
+ .basefn-app-layout__topbar--above {
78
+ position: sticky;
79
+ top: 0;
80
+ width: 100%;
81
+ z-index: 201; /* Above sidebar */
82
+ }
83
+
46
84
  .basefn-app-layout__content {
47
85
  flex: 1;
48
86
  display: flex;
@@ -97,4 +135,17 @@
97
135
  .basefn-app-layout--sidebar-open .basefn-app-layout__sidebar-backdrop {
98
136
  display: block;
99
137
  }
138
+
139
+ /* When topbar is above, adjust sidebar and backdrop position */
140
+ .basefn-app-layout--topbar-above .basefn-app-layout__sidebar-backdrop {
141
+ top: 64px; /* Start below topbar (md) */
142
+ }
143
+
144
+ .basefn-app-layout--topbar-above.basefn-app-layout--topbar-sm .basefn-app-layout__sidebar-backdrop {
145
+ top: 56px;
146
+ }
147
+
148
+ .basefn-app-layout--topbar-above.basefn-app-layout--topbar-lg .basefn-app-layout__sidebar-backdrop {
149
+ top: 72px;
150
+ }
100
151
  }
@@ -3,6 +3,7 @@
3
3
  open Xote
4
4
 
5
5
  type contentWidth = FullWidth | Contained
6
+ type topbarPosition = Inline | AboveAll
6
7
 
7
8
  @jsx.component
8
9
  let make = (
@@ -13,6 +14,8 @@ let make = (
13
14
  ~noPadding: bool=false,
14
15
  ~sidebarSize: option<string>=?, // "sm" | "md" | "lg"
15
16
  ~sidebarCollapsed: bool=false,
17
+ ~topbarPosition: topbarPosition=Inline,
18
+ ~topbarSize: option<string>=?, // "sm" | "md" | "lg"
16
19
  ) => {
17
20
  let sidebarOpen = Signal.make(false)
18
21
 
@@ -24,10 +27,24 @@ let make = (
24
27
  | _ => ""
25
28
  }
26
29
  let collapsedClass = sidebarCollapsed ? " basefn-app-layout--sidebar-collapsed" : ""
30
+ let topbarPositionClass = switch topbarPosition {
31
+ | AboveAll => " basefn-app-layout--topbar-above"
32
+ | Inline => ""
33
+ }
34
+ let topbarSizeClass = switch (topbarPosition, topbarSize) {
35
+ | (AboveAll, Some("sm")) => " basefn-app-layout--topbar-sm"
36
+ | (AboveAll, Some("lg")) => " basefn-app-layout--topbar-lg"
37
+ | _ => ""
38
+ }
27
39
  let sidebarOpenClass = Computed.make(() =>
28
40
  Signal.get(sidebarOpen) ? " basefn-app-layout--sidebar-open" : ""
29
41
  )
30
- "basefn-app-layout" ++ hasSidebar ++ sidebarSizeClass ++ collapsedClass
42
+ "basefn-app-layout" ++
43
+ hasSidebar ++
44
+ sidebarSizeClass ++
45
+ collapsedClass ++
46
+ topbarPositionClass ++
47
+ topbarSizeClass
31
48
  }
32
49
 
33
50
  let getContentClass = () => {
@@ -51,24 +68,35 @@ let make = (
51
68
  )
52
69
  })}
53
70
  >
54
- {switch sidebar {
55
- | Some(sidebarContent) =>
56
- <>
57
- <div class="basefn-app-layout__sidebar"> {sidebarContent} </div>
58
- <div
59
- class="basefn-app-layout__sidebar-backdrop" onClick={_ => Signal.set(sidebarOpen, false)}
60
- />
61
- </>
62
- | None => <> </>
71
+ {switch (topbarPosition, topbar) {
72
+ | (AboveAll, Some(topbarContent)) =>
73
+ <div class="basefn-app-layout__topbar basefn-app-layout__topbar--above">
74
+ {topbarContent}
75
+ </div>
76
+ | _ => <> </>
63
77
  }}
64
- <div class="basefn-app-layout__main-wrapper">
65
- {switch topbar {
66
- | Some(topbarContent) => <div class="basefn-app-layout__topbar"> {topbarContent} </div>
78
+ <div class="basefn-app-layout__body">
79
+ {switch sidebar {
80
+ | Some(sidebarContent) =>
81
+ <>
82
+ <div class="basefn-app-layout__sidebar"> {sidebarContent} </div>
83
+ <div
84
+ class="basefn-app-layout__sidebar-backdrop"
85
+ onClick={_ => Signal.set(sidebarOpen, false)}
86
+ />
87
+ </>
67
88
  | None => <> </>
68
89
  }}
69
- <main class="basefn-app-layout__content">
70
- <div class={getContentClass()}> {children} </div>
71
- </main>
90
+ <div class="basefn-app-layout__main-wrapper">
91
+ {switch (topbarPosition, topbar) {
92
+ | (Inline, Some(topbarContent)) =>
93
+ <div class="basefn-app-layout__topbar"> {topbarContent} </div>
94
+ | _ => <> </>
95
+ }}
96
+ <main class="basefn-app-layout__content">
97
+ <div class={getContentClass()}> {children} </div>
98
+ </main>
99
+ </div>
72
100
  </div>
73
101
  </div>
74
102
  }
@@ -8,6 +8,8 @@ import './Basefn__AppLayout.css'
8
8
  ;
9
9
 
10
10
  function Basefn__AppLayout(props) {
11
+ let topbarSize = props.topbarSize;
12
+ let __topbarPosition = props.topbarPosition;
11
13
  let __sidebarCollapsed = props.sidebarCollapsed;
12
14
  let sidebarSize = props.sidebarSize;
13
15
  let __noPadding = props.noPadding;
@@ -17,6 +19,7 @@ function Basefn__AppLayout(props) {
17
19
  let contentWidth = __contentWidth !== undefined ? __contentWidth : "FullWidth";
18
20
  let noPadding = __noPadding !== undefined ? __noPadding : false;
19
21
  let sidebarCollapsed = __sidebarCollapsed !== undefined ? __sidebarCollapsed : false;
22
+ let topbarPosition = __topbarPosition !== undefined ? __topbarPosition : "Inline";
20
23
  let sidebarOpen = Xote.Signal.make(false, undefined, undefined);
21
24
  let getLayoutClass = () => {
22
25
  let hasSidebar = Core__Option.isSome(sidebar) ? " basefn-app-layout--has-sidebar" : "";
@@ -36,6 +39,23 @@ function Basefn__AppLayout(props) {
36
39
  sidebarSizeClass = "";
37
40
  }
38
41
  let collapsedClass = sidebarCollapsed ? " basefn-app-layout--sidebar-collapsed" : "";
42
+ let topbarPositionClass;
43
+ topbarPositionClass = topbarPosition === "Inline" ? "" : " basefn-app-layout--topbar-above";
44
+ let topbarSizeClass;
45
+ if (topbarPosition === "Inline" || topbarSize === undefined) {
46
+ topbarSizeClass = "";
47
+ } else {
48
+ switch (topbarSize) {
49
+ case "lg" :
50
+ topbarSizeClass = " basefn-app-layout--topbar-lg";
51
+ break;
52
+ case "sm" :
53
+ topbarSizeClass = " basefn-app-layout--topbar-sm";
54
+ break;
55
+ default:
56
+ topbarSizeClass = "";
57
+ }
58
+ }
39
59
  Xote.Computed.make(() => {
40
60
  if (Xote.Signal.get(sidebarOpen)) {
41
61
  return " basefn-app-layout--sidebar-open";
@@ -43,7 +63,7 @@ function Basefn__AppLayout(props) {
43
63
  return "";
44
64
  }
45
65
  }, undefined);
46
- return "basefn-app-layout" + hasSidebar + sidebarSizeClass + collapsedClass;
66
+ return "basefn-app-layout" + hasSidebar + sidebarSizeClass + collapsedClass + topbarPositionClass + topbarSizeClass;
47
67
  };
48
68
  let getContentClass = () => {
49
69
  let widthClass;
@@ -51,6 +71,16 @@ function Basefn__AppLayout(props) {
51
71
  let paddingClass = noPadding ? " basefn-app-layout__content-inner--no-padding" : "";
52
72
  return "basefn-app-layout__content-inner" + widthClass + paddingClass;
53
73
  };
74
+ let tmp;
75
+ tmp = topbarPosition === "Inline" || topbar === undefined ? Xote__JSX.jsx(Xote__JSX.jsxFragment, {}) : Xote__JSX.Elements.jsx("div", {
76
+ class: "basefn-app-layout__topbar basefn-app-layout__topbar--above",
77
+ children: topbar
78
+ });
79
+ let tmp$1;
80
+ tmp$1 = topbarPosition === "Inline" && topbar !== undefined ? Xote__JSX.Elements.jsx("div", {
81
+ class: "basefn-app-layout__topbar",
82
+ children: topbar
83
+ }) : Xote__JSX.jsx(Xote__JSX.jsxFragment, {});
54
84
  return Xote__JSX.Elements.jsxs("div", {
55
85
  class: Xote.Computed.make(() => getLayoutClass() + Xote.Signal.get(Xote.Computed.make(() => {
56
86
  if (Xote.Signal.get(sidebarOpen)) {
@@ -60,31 +90,34 @@ function Basefn__AppLayout(props) {
60
90
  }
61
91
  }, undefined)), undefined),
62
92
  children: Xote__JSX.array([
63
- sidebar !== undefined ? Xote__JSX.jsxs(Xote__JSX.jsxFragment, {
64
- children: Xote__JSX.array([
65
- Xote__JSX.Elements.jsx("div", {
66
- class: "basefn-app-layout__sidebar",
67
- children: sidebar
68
- }),
69
- Xote__JSX.Elements.jsx("div", {
70
- class: "basefn-app-layout__sidebar-backdrop",
71
- onClick: param => Xote.Signal.set(sidebarOpen, false)
72
- })
73
- ])
74
- }) : Xote__JSX.jsx(Xote__JSX.jsxFragment, {}),
93
+ tmp,
75
94
  Xote__JSX.Elements.jsxs("div", {
76
- class: "basefn-app-layout__main-wrapper",
95
+ class: "basefn-app-layout__body",
77
96
  children: Xote__JSX.array([
78
- topbar !== undefined ? Xote__JSX.Elements.jsx("div", {
79
- class: "basefn-app-layout__topbar",
80
- children: topbar
97
+ sidebar !== undefined ? Xote__JSX.jsxs(Xote__JSX.jsxFragment, {
98
+ children: Xote__JSX.array([
99
+ Xote__JSX.Elements.jsx("div", {
100
+ class: "basefn-app-layout__sidebar",
101
+ children: sidebar
102
+ }),
103
+ Xote__JSX.Elements.jsx("div", {
104
+ class: "basefn-app-layout__sidebar-backdrop",
105
+ onClick: param => Xote.Signal.set(sidebarOpen, false)
106
+ })
107
+ ])
81
108
  }) : Xote__JSX.jsx(Xote__JSX.jsxFragment, {}),
82
- Xote__JSX.Elements.jsx("main", {
83
- class: "basefn-app-layout__content",
84
- children: Xote__JSX.Elements.jsx("div", {
85
- class: getContentClass(),
86
- children: props.children
87
- })
109
+ Xote__JSX.Elements.jsxs("div", {
110
+ class: "basefn-app-layout__main-wrapper",
111
+ children: Xote__JSX.array([
112
+ tmp$1,
113
+ Xote__JSX.Elements.jsx("main", {
114
+ class: "basefn-app-layout__content",
115
+ children: Xote__JSX.Elements.jsx("div", {
116
+ class: getContentClass(),
117
+ children: props.children
118
+ })
119
+ })
120
+ ])
88
121
  })
89
122
  ])
90
123
  })
@@ -15,9 +15,6 @@
15
15
  border-bottom: 1px solid var(--basefn-border-primary);
16
16
  }
17
17
 
18
- .basefn-topbar--scrolling {
19
- }
20
-
21
18
  .basefn-topbar__left {
22
19
  display: flex;
23
20
  align-items: center;
@@ -28,19 +28,7 @@ let make = (
28
28
  ~onMenuClick: option<unit => unit>=?,
29
29
  ~size: size=Md,
30
30
  ) => {
31
- let scrolling = Signal.make(false)
32
- let class = Computed.make(() => {
33
- let sizeClass = " basefn-topbar--" ++ sizeToString(size)
34
- let scrollingClass = Signal.get(scrolling) ? " basefn-topbar--scrolling" : ""
35
- "basefn-topbar" ++ sizeClass ++ scrollingClass
36
- })
37
-
38
- let _ = Effect.run(() => {
39
- Basefn__Dom.addEventListener("scroll", () => {
40
- let scrollY = %raw("window.scrollY")
41
- Signal.set(scrolling, scrollY >= 64)
42
- })
43
- })
31
+ let class = "basefn-topbar basefn-topbar--" ++ sizeToString(size)
44
32
 
45
33
  <header class>
46
34
  <div class="basefn-topbar__left">
@@ -2,7 +2,6 @@
2
2
 
3
3
  import * as Xote from "xote/src/Xote.res.mjs";
4
4
  import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
- import * as Basefn__Dom from "../Basefn__Dom.res.mjs";
6
5
 
7
6
  import './Basefn__Topbar.css'
8
7
  ;
@@ -27,16 +26,7 @@ function Basefn__Topbar(props) {
27
26
  let navItems = props.navItems;
28
27
  let logo = props.logo;
29
28
  let size = __size !== undefined ? __size : "Md";
30
- let scrolling = Xote.Signal.make(false, undefined, undefined);
31
- let $$class = Xote.Computed.make(() => {
32
- let sizeClass = " basefn-topbar--" + sizeToString(size);
33
- let scrollingClass = Xote.Signal.get(scrolling) ? " basefn-topbar--scrolling" : "";
34
- return "basefn-topbar" + sizeClass + scrollingClass;
35
- }, undefined);
36
- Xote.Effect.run(() => Basefn__Dom.addEventListener("scroll", () => {
37
- let scrollY = window.scrollY;
38
- Xote.Signal.set(scrolling, scrollY >= 64);
39
- }), undefined);
29
+ let $$class = "basefn-topbar basefn-topbar--" + sizeToString(size);
40
30
  return Xote__JSX.Elements.jsxs("header", {
41
31
  class: $$class,
42
32
  children: Xote__JSX.array([