@toyonix/web-kit 0.1.2 → 0.1.3
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/dist/css/components.css +60 -12
- package/dist/react/AppShell.js +25 -0
- package/package.json +1 -1
package/dist/css/components.css
CHANGED
|
@@ -111,32 +111,80 @@
|
|
|
111
111
|
outline: var(--tx-border-width) solid var(--tx-border);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
/*
|
|
114
|
+
/*
|
|
115
|
+
* Narrow screens: stay on one row. The header gets more compact, and if the app links still
|
|
116
|
+
* don't fit, they scroll sideways (AppShell scrolls the current app into view).
|
|
117
|
+
*/
|
|
115
118
|
@media (max-width: 640px) {
|
|
116
119
|
.tx-header__inner {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
padding-top: 10px;
|
|
120
|
-
padding-bottom: 8px;
|
|
121
|
-
min-height: 0;
|
|
120
|
+
gap: 10px;
|
|
121
|
+
min-height: 56px;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
.tx-
|
|
125
|
-
|
|
124
|
+
.tx-logo {
|
|
125
|
+
flex: none;
|
|
126
|
+
gap: 8px;
|
|
127
|
+
font-size: 20px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.tx-logo__mark {
|
|
131
|
+
width: 26px;
|
|
132
|
+
height: 26px;
|
|
133
|
+
font-size: 13px;
|
|
126
134
|
}
|
|
127
135
|
|
|
128
136
|
.tx-nav {
|
|
129
|
-
|
|
137
|
+
flex: 0 1 auto;
|
|
130
138
|
flex-wrap: nowrap;
|
|
131
|
-
width:
|
|
132
|
-
|
|
133
|
-
padding: 4px 3px 6px;
|
|
139
|
+
min-width: 0;
|
|
140
|
+
padding: 3px; /* room for the current app's outline */
|
|
134
141
|
overflow-x: auto;
|
|
135
142
|
scrollbar-width: none;
|
|
136
143
|
}
|
|
137
144
|
|
|
145
|
+
.tx-nav::-webkit-scrollbar {
|
|
146
|
+
display: none;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Fade only the edges that have more links beyond them (set by AppShell), hinting at the scroll. */
|
|
150
|
+
.tx-nav[data-more-left],
|
|
151
|
+
.tx-nav[data-more-right] {
|
|
152
|
+
--tx-nav-fade-left: 0px;
|
|
153
|
+
--tx-nav-fade-right: 0px;
|
|
154
|
+
-webkit-mask-image: linear-gradient(
|
|
155
|
+
to right,
|
|
156
|
+
transparent,
|
|
157
|
+
#000 var(--tx-nav-fade-left),
|
|
158
|
+
#000 calc(100% - var(--tx-nav-fade-right)),
|
|
159
|
+
transparent
|
|
160
|
+
);
|
|
161
|
+
mask-image: linear-gradient(
|
|
162
|
+
to right,
|
|
163
|
+
transparent,
|
|
164
|
+
#000 var(--tx-nav-fade-left),
|
|
165
|
+
#000 calc(100% - var(--tx-nav-fade-right)),
|
|
166
|
+
transparent
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.tx-nav[data-more-left] {
|
|
171
|
+
--tx-nav-fade-left: 22px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.tx-nav[data-more-right] {
|
|
175
|
+
--tx-nav-fade-right: 22px;
|
|
176
|
+
}
|
|
177
|
+
|
|
138
178
|
.tx-nav a {
|
|
139
179
|
flex: none;
|
|
180
|
+
padding: 6px 9px;
|
|
181
|
+
font-size: 14px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.tx-header__inner .tx-icon-btn {
|
|
185
|
+
flex: none;
|
|
186
|
+
width: 36px;
|
|
187
|
+
height: 36px;
|
|
140
188
|
}
|
|
141
189
|
}
|
|
142
190
|
|
package/dist/react/AppShell.js
CHANGED
|
@@ -3,6 +3,7 @@ import { appHref, getAppId } from "../env.js";
|
|
|
3
3
|
import { navApps } from "../registry/index.js";
|
|
4
4
|
import { ThemeToggle } from "./ThemeToggle.js";
|
|
5
5
|
import { useRegistry } from "./use-registry.js";
|
|
6
|
+
import { useEffect, useRef } from "react";
|
|
6
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
//#region src/react/AppShell.tsx
|
|
8
9
|
/**
|
|
@@ -12,6 +13,29 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
12
13
|
function AppShell({ children, registry, appTitle, nav, footer }) {
|
|
13
14
|
const appId = getAppId();
|
|
14
15
|
const apps = navApps(useRegistry(registry));
|
|
16
|
+
const navRef = useRef(null);
|
|
17
|
+
const appCount = apps.length;
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const nav = navRef.current;
|
|
20
|
+
if (!nav) return;
|
|
21
|
+
const markEdges = () => {
|
|
22
|
+
const max = nav.scrollWidth - nav.clientWidth;
|
|
23
|
+
nav.toggleAttribute("data-more-left", max > 1 && nav.scrollLeft > 1);
|
|
24
|
+
nav.toggleAttribute("data-more-right", max > 1 && nav.scrollLeft < max - 1);
|
|
25
|
+
};
|
|
26
|
+
const update = () => {
|
|
27
|
+
const current = nav.querySelector("[aria-current]");
|
|
28
|
+
if (current && nav.scrollWidth > nav.clientWidth + 1) nav.scrollLeft = current.offsetLeft - (nav.clientWidth - current.offsetWidth) / 2;
|
|
29
|
+
markEdges();
|
|
30
|
+
};
|
|
31
|
+
update();
|
|
32
|
+
nav.addEventListener("scroll", markEdges, { passive: true });
|
|
33
|
+
window.addEventListener("resize", update);
|
|
34
|
+
return () => {
|
|
35
|
+
nav.removeEventListener("scroll", markEdges);
|
|
36
|
+
window.removeEventListener("resize", update);
|
|
37
|
+
};
|
|
38
|
+
}, [appCount]);
|
|
15
39
|
if (appId !== "root" && !apps.some((app) => app.id === appId)) apps.push({
|
|
16
40
|
id: appId,
|
|
17
41
|
title: appTitle ?? appId,
|
|
@@ -42,6 +66,7 @@ function AppShell({ children, registry, appTitle, nav, footer }) {
|
|
|
42
66
|
}), /* @__PURE__ */ jsx("span", { children: "toyonix" })]
|
|
43
67
|
}),
|
|
44
68
|
/* @__PURE__ */ jsxs("nav", {
|
|
69
|
+
ref: navRef,
|
|
45
70
|
className: "tx-nav",
|
|
46
71
|
"aria-label": "toyonix apps",
|
|
47
72
|
children: [/* @__PURE__ */ jsx("a", {
|