@protobase/ui 0.23.6 → 0.23.8
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/app/current-address.d.ts +4 -3
- package/dist/app/current-address.js +1 -0
- package/dist/app/displays/calendar-controls.js +17 -49
- package/dist/app/displays/calendar-event.js +2 -2
- package/dist/app/displays/calendar-range.js +19 -9
- package/dist/app/displays/display-controls.js +2 -1
- package/dist/app/displays/list-displays.js +8 -1
- package/dist/app/displays/period-controls.js +55 -0
- package/dist/app/displays/timeline-display.js +225 -0
- package/dist/app/displays/timeline-range.js +140 -0
- package/dist/app/displays/timeline-row.js +42 -0
- package/dist/app/displays/timeline-scale.js +50 -0
- package/dist/app/embedded-list/embedded-list.js +7 -0
- package/dist/app/index.html +2 -0
- package/dist/app/list-page.js +11 -1
- package/dist/format/date.js +6 -1
- package/dist/package.js +1 -1
- package/dist/shell/assets/app-BaOeRmvJ.js +69 -0
- package/dist/shell/assets/{index-CY5B9PIg.js → index-BSpJh7ky.js} +1 -1
- package/dist/shell/assets/index-Br0ZlvVS.css +2 -0
- package/dist/shell/assets/{maplibre-D4ace4wn.js → maplibre--RHVslik.js} +1 -1
- package/dist/shell/assets/{markdown-content-JU2jw1Kr.js → markdown-content-CNP__2Lb.js} +1 -1
- package/dist/shell/assets/{record-map-B8GB--Ku.js → record-map-CS2kj78D.js} +1 -1
- package/dist/shell/assets/{records-map-BUfPiD0T.js → records-map-D66qm5NI.js} +1 -1
- package/dist/shell/assets/{shared-protobase-ui-C0Ld98uO.js → shared-protobase-ui-C2BPkI-k.js} +1 -1
- package/dist/shell/index.html +7 -4
- package/dist/shell/protobase.shell.json +3 -2
- package/dist/shell/protobase.sw.js +33 -0
- package/package.json +4 -4
- package/dist/shell/assets/app-ByxJ0Flo.js +0 -69
- package/dist/shell/assets/index-B-IciGPG.css +0 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { CalendarEvent, eventTitle } from "./calendar-event.js";
|
|
3
|
+
import { barOf } from "./timeline-range.js";
|
|
4
|
+
import { share, timelineGrid } from "./timeline-scale.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/app/displays/timeline-row.tsx
|
|
7
|
+
/**
|
|
8
|
+
* A record of a timeline: its title, and its bar over the days it is on, an event chip as wide as those days, cut
|
|
9
|
+
* square where it goes on before or after them. The bar is the link to the record, and is picked up to move it.
|
|
10
|
+
*/
|
|
11
|
+
const TimelineRow = ({ model, view, display, row, days, movable, dragged }) => {
|
|
12
|
+
const bar = barOf(row.record, display, model, days);
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
14
|
+
className: cn(timelineGrid, "relative border-b border-border last:border-b-0"),
|
|
15
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
16
|
+
"aria-hidden": true,
|
|
17
|
+
className: "truncate px-2 pt-1 text-xs sm:py-1.5",
|
|
18
|
+
children: eventTitle(model, view, display, row)
|
|
19
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
20
|
+
className: "relative h-7",
|
|
21
|
+
children: bar && /* @__PURE__ */ jsx("div", {
|
|
22
|
+
className: "absolute top-1/2 -translate-y-1/2",
|
|
23
|
+
style: {
|
|
24
|
+
left: share(bar.first, days.length),
|
|
25
|
+
width: share(bar.last - bar.first + 1, days.length)
|
|
26
|
+
},
|
|
27
|
+
children: /* @__PURE__ */ jsx(CalendarEvent, {
|
|
28
|
+
model,
|
|
29
|
+
view,
|
|
30
|
+
display,
|
|
31
|
+
row,
|
|
32
|
+
day: bar.start,
|
|
33
|
+
movable,
|
|
34
|
+
dragged,
|
|
35
|
+
className: cn(bar.before && "rounded-l-none border-l-0", bar.after && "rounded-r-none border-r-0")
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
})]
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { TimelineRow };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/app/displays/timeline-scale.tsx
|
|
4
|
+
/** A timeline's columns: the records' titles beside their bars, above them on a phone. */
|
|
5
|
+
const timelineGrid = "grid grid-cols-1 sm:grid-cols-[12rem_minmax(0,1fr)]";
|
|
6
|
+
/** Where `count` days of `total` end, as a share of the bars' width. */
|
|
7
|
+
const share = (count, total) => `${count / total * 100}%`;
|
|
8
|
+
/** The scale over a timeline's rows: the marks of its days or months, today's marked. */
|
|
9
|
+
const TimelineScale = ({ ticks, days, today, label, trackRef }) => /* @__PURE__ */ jsxs("div", {
|
|
10
|
+
className: cn(timelineGrid, "border-b border-border bg-surface"),
|
|
11
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
12
|
+
className: "hidden truncate px-2 py-1 text-xs font-medium text-muted-foreground sm:block",
|
|
13
|
+
children: label
|
|
14
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
15
|
+
ref: trackRef,
|
|
16
|
+
"aria-hidden": true,
|
|
17
|
+
className: "relative h-6",
|
|
18
|
+
children: ticks.map((tick) => /* @__PURE__ */ jsx("span", {
|
|
19
|
+
className: cn("absolute inset-y-0 items-center truncate px-1 text-xs tabular-nums text-muted-foreground", tick.index > 0 ? "border-l border-border" : "border-border sm:border-l", tick.minor ? "hidden sm:flex" : "flex", tick.span === 1 && days[tick.index] === today && "font-medium text-primary"),
|
|
20
|
+
style: {
|
|
21
|
+
left: share(tick.index, days.length),
|
|
22
|
+
width: share(tick.span, days.length)
|
|
23
|
+
},
|
|
24
|
+
children: tick.label
|
|
25
|
+
}, tick.index))
|
|
26
|
+
})]
|
|
27
|
+
});
|
|
28
|
+
/** The lines behind a timeline's rows where each mark starts, and today's day shaded. */
|
|
29
|
+
const TimelineLines = ({ ticks, days, today }) => {
|
|
30
|
+
const at = days.indexOf(today);
|
|
31
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
32
|
+
"aria-hidden": true,
|
|
33
|
+
className: cn(timelineGrid, "pointer-events-none absolute inset-0"),
|
|
34
|
+
children: [/* @__PURE__ */ jsx("span", { className: "hidden sm:block" }), /* @__PURE__ */ jsxs("div", {
|
|
35
|
+
className: "relative",
|
|
36
|
+
children: [at >= 0 && /* @__PURE__ */ jsx("span", {
|
|
37
|
+
className: "absolute inset-y-0 bg-primary/10",
|
|
38
|
+
style: {
|
|
39
|
+
left: share(at, days.length),
|
|
40
|
+
width: share(1, days.length)
|
|
41
|
+
}
|
|
42
|
+
}), ticks.map((tick) => /* @__PURE__ */ jsx("span", {
|
|
43
|
+
className: cn("absolute inset-y-0 w-px bg-border", (tick.minor || tick.index === 0) && "hidden sm:block"),
|
|
44
|
+
style: { left: share(tick.index, days.length) }
|
|
45
|
+
}, tick.index))]
|
|
46
|
+
})]
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { TimelineLines, TimelineScale, share, timelineGrid };
|
|
@@ -13,6 +13,7 @@ import { DataGrid } from "../../data-grid/data-grid.js";
|
|
|
13
13
|
import { viewAllAddress } from "./embedded-display.js";
|
|
14
14
|
import { BoardDisplay } from "../displays/board-display.js";
|
|
15
15
|
import { CalendarDisplay } from "../displays/calendar-display.js";
|
|
16
|
+
import { TimelineDisplay } from "../displays/timeline-display.js";
|
|
16
17
|
import { CardsDisplay } from "../displays/cards-display.js";
|
|
17
18
|
import { CustomDisplay } from "../displays/custom-display.js";
|
|
18
19
|
import { MapDisplay } from "../displays/map-display.js";
|
|
@@ -181,6 +182,12 @@ const EmbeddedList = ({ model, view, filter, sort, columns, limit, display, empt
|
|
|
181
182
|
display: shown,
|
|
182
183
|
fields,
|
|
183
184
|
filter
|
|
185
|
+
}) : shown.kind === "timeline" ? /* @__PURE__ */ jsx(TimelineDisplay, {
|
|
186
|
+
model,
|
|
187
|
+
view,
|
|
188
|
+
display: shown,
|
|
189
|
+
fields,
|
|
190
|
+
filter
|
|
184
191
|
}) : /* @__PURE__ */ jsx(CustomDisplay, {
|
|
185
192
|
display: shown,
|
|
186
193
|
list
|
package/dist/app/index.html
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
6
|
<title>Protobase</title>
|
|
7
|
+
<!-- Makes the app installable, named for the app: the server answers it, as it alone knows the name. -->
|
|
8
|
+
<link rel="manifest" href="/api/manifest.webmanifest" />
|
|
7
9
|
<!-- The theme before the first paint, so a dark page never flashes light: as theme/theme-preference.ts resolves it, the choice stored in this browser, else the system's. -->
|
|
8
10
|
<script>
|
|
9
11
|
var stored = null
|
package/dist/app/list-page.js
CHANGED
|
@@ -34,6 +34,7 @@ import { listHandOrder } from "./hand-order/hand-order.js";
|
|
|
34
34
|
import { useDisplayRows } from "./displays/use-display-rows.js";
|
|
35
35
|
import { BoardDisplay } from "./displays/board-display.js";
|
|
36
36
|
import { CalendarDisplay } from "./displays/calendar-display.js";
|
|
37
|
+
import { TimelineDisplay } from "./displays/timeline-display.js";
|
|
37
38
|
import { CustomDisplay } from "./displays/custom-display.js";
|
|
38
39
|
import { MapDisplay } from "./displays/map-display.js";
|
|
39
40
|
import { DisplaySwitch, SortMenu } from "./displays/display-controls.js";
|
|
@@ -213,7 +214,7 @@ const LoadedList = ({ model, address, scope, heading }) => {
|
|
|
213
214
|
setFilter(state, text ? [...others, where$1.search(text)] : others);
|
|
214
215
|
};
|
|
215
216
|
const plural = view?.names?.plural ?? humanize(resource);
|
|
216
|
-
const sorted = display?.kind === "calendar" || display?.kind === "board" && boardRank(model) ? void 0 : display;
|
|
217
|
+
const sorted = display?.kind === "calendar" || display?.kind === "timeline" || display?.kind === "board" && boardRank(model) ? void 0 : display;
|
|
217
218
|
const sortMenu = sorted && /* @__PURE__ */ jsx(SortMenu, {
|
|
218
219
|
model,
|
|
219
220
|
view,
|
|
@@ -446,6 +447,15 @@ const LoadedList = ({ model, address, scope, heading }) => {
|
|
|
446
447
|
at: address.calendar,
|
|
447
448
|
linkTo: (calendar) => listTo({ calendar })
|
|
448
449
|
});
|
|
450
|
+
if (display.kind === "timeline") return /* @__PURE__ */ jsx(TimelineDisplay, {
|
|
451
|
+
model,
|
|
452
|
+
view,
|
|
453
|
+
display,
|
|
454
|
+
fields: loaded,
|
|
455
|
+
filter: loadFilter,
|
|
456
|
+
at: address.timeline,
|
|
457
|
+
linkTo: (timeline) => listTo({ timeline })
|
|
458
|
+
});
|
|
449
459
|
return /* @__PURE__ */ jsx(CustomDisplay, {
|
|
450
460
|
display,
|
|
451
461
|
list: displayRows
|
package/dist/format/date.js
CHANGED
|
@@ -19,6 +19,7 @@ const month = dateFormat("month", {
|
|
|
19
19
|
month: "long",
|
|
20
20
|
year: "numeric"
|
|
21
21
|
});
|
|
22
|
+
const monthName = dateFormat("monthName", { month: "long" });
|
|
22
23
|
const weekday = dateFormat("weekday", { weekday: "short" });
|
|
23
24
|
const weekdayDate = dateFormat("weekdayDate", {
|
|
24
25
|
weekday: "long",
|
|
@@ -49,6 +50,10 @@ const formatDateTime = (ms, zone = viewerZone()) => {
|
|
|
49
50
|
};
|
|
50
51
|
/** "October 2026". */
|
|
51
52
|
const formatMonth = (ms) => month().format(ms);
|
|
53
|
+
/** "October". */
|
|
54
|
+
const formatMonthName = (ms) => monthName().format(ms);
|
|
55
|
+
/** "October – December 2026": the months from `from` to `to`, both included. */
|
|
56
|
+
const formatMonthRange = (from, to) => month().formatRange(from, to);
|
|
52
57
|
/** "Mon". */
|
|
53
58
|
const formatWeekday = (ms) => weekday().format(ms);
|
|
54
59
|
/** "Monday, 12 Oct 2026". */
|
|
@@ -79,4 +84,4 @@ const formatRelativeTime = (seconds) => {
|
|
|
79
84
|
return relative().format(-Math.sign(seconds) * Math.floor(away / size), unit);
|
|
80
85
|
};
|
|
81
86
|
//#endregion
|
|
82
|
-
export { formatAgo, formatDate, formatDateTime, formatDayRange, formatDayShort, formatMonth, formatRelativeTime, formatTime, formatWeekday, formatWeekdayDate };
|
|
87
|
+
export { formatAgo, formatDate, formatDateTime, formatDayRange, formatDayShort, formatMonth, formatMonthName, formatMonthRange, formatRelativeTime, formatTime, formatWeekday, formatWeekdayDate };
|
package/dist/package.js
CHANGED