@mim/histui 0.2.1 → 0.3.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/README.md +5 -1
- package/package.json +1 -1
- package/src/default-config.js +1 -0
- package/src/i18n.js +24 -0
- package/src/index.d.ts +6 -0
- package/src/index.js +28 -0
- package/src/styles.css +45 -0
- package/src/timeline-view.js +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Histui
|
|
2
2
|
|
|
3
|
-
Histui is a reusable, framework-agnostic interactive history timeline package. It can render PastStruct datasets or already-normalized records into a zoomable, pannable, responsive timeline with LOD, clustering, a zoom navigator, hover-linked connectors, blueprint-style measurement indicators, axis placement controls, themes, Persian/English UI strings, and explode mode.
|
|
3
|
+
Histui is a reusable, framework-agnostic interactive history timeline package. It can render PastStruct datasets or already-normalized records into a zoomable, pannable, responsive timeline with LOD, clustering, a zoom navigator, hover-linked connectors, blueprint-style measurement indicators, axis placement controls, themes, broadcast display mode, Persian/English UI strings, and explode mode.
|
|
4
4
|
|
|
5
5
|
## Files
|
|
6
6
|
|
|
@@ -30,6 +30,7 @@ const histui = createHistuiTimeline({
|
|
|
30
30
|
data: pastStructDataset,
|
|
31
31
|
language: "en",
|
|
32
32
|
themeId: "obsidian-lab",
|
|
33
|
+
displayMode: "standard",
|
|
33
34
|
explodeEnabled: false,
|
|
34
35
|
onSelect(record) {
|
|
35
36
|
console.log("selected", record.id);
|
|
@@ -90,6 +91,7 @@ Common options:
|
|
|
90
91
|
- `language`: default `"en"`.
|
|
91
92
|
- `direction`: optional text direction override.
|
|
92
93
|
- `themeId` or `theme`: built-in theme id or custom theme object.
|
|
94
|
+
- `displayMode`: `"standard"` or `"broadcast"`. Broadcast mode increases legibility and uses overlay-friendly timeline styling.
|
|
93
95
|
- `controls`: render built-in timeline controls. Default `true`.
|
|
94
96
|
- `replace`: clear the container before mounting. Default `true`.
|
|
95
97
|
- `filters`: initial filter object.
|
|
@@ -120,6 +122,8 @@ Common options:
|
|
|
120
122
|
- `setExplodeEnabled(enabled)`
|
|
121
123
|
- `setMeasurementOptions(options)`
|
|
122
124
|
- `setMeasurementEnabled(enabled)`
|
|
125
|
+
- `setDisplayMode("standard" | "broadcast")`
|
|
126
|
+
- `setBroadcastMode(enabled)`
|
|
123
127
|
- `setLanguage(language, direction)`
|
|
124
128
|
- `setTheme(themeOrId)`
|
|
125
129
|
- `getState()`
|
package/package.json
CHANGED
package/src/default-config.js
CHANGED
package/src/i18n.js
CHANGED
|
@@ -29,6 +29,18 @@ export const UI_STRINGS = {
|
|
|
29
29
|
uncertainOnly: "Uncertain dates",
|
|
30
30
|
lod: "Adaptive detail",
|
|
31
31
|
explode: "Explode",
|
|
32
|
+
broadcast: "Broadcast",
|
|
33
|
+
broadcastMode: "Broadcast Mode",
|
|
34
|
+
broadcastSettings: "Broadcast settings",
|
|
35
|
+
exitBroadcast: "Exit broadcast",
|
|
36
|
+
preset: "Preset",
|
|
37
|
+
background: "Background",
|
|
38
|
+
showDetails: "Show selected details",
|
|
39
|
+
restoreOnLoad: "Restore on load",
|
|
40
|
+
copyUrl: "Copy viewer URL",
|
|
41
|
+
copied: "Copied",
|
|
42
|
+
settings: "Settings",
|
|
43
|
+
close: "Close",
|
|
32
44
|
resetFilters: "Reset",
|
|
33
45
|
zoomIn: "Zoom in",
|
|
34
46
|
zoomOut: "Zoom out",
|
|
@@ -113,6 +125,18 @@ export const UI_STRINGS = {
|
|
|
113
125
|
uncertainOnly: "تاریخ نامطمئن",
|
|
114
126
|
lod: "جزئیات تطبیقی",
|
|
115
127
|
explode: "نمای انفجاری",
|
|
128
|
+
broadcast: "پخش",
|
|
129
|
+
broadcastMode: "حالت پخش",
|
|
130
|
+
broadcastSettings: "تنظیمات پخش",
|
|
131
|
+
exitBroadcast: "خروج از پخش",
|
|
132
|
+
preset: "پیش تنظیم",
|
|
133
|
+
background: "پس زمینه",
|
|
134
|
+
showDetails: "نمایش جزئیات انتخاب",
|
|
135
|
+
restoreOnLoad: "بازیابی هنگام بارگذاری",
|
|
136
|
+
copyUrl: "کپی نشانی نما",
|
|
137
|
+
copied: "کپی شد",
|
|
138
|
+
settings: "تنظیمات",
|
|
139
|
+
close: "بستن",
|
|
116
140
|
resetFilters: "بازنشانی",
|
|
117
141
|
zoomIn: "بزرگ نمایی",
|
|
118
142
|
zoomOut: "کوچک نمایی",
|
package/src/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type HistuiOrientation = "auto" | "horizontal" | "vertical";
|
|
2
2
|
export type HistuiAxisPlacement = "center" | "side-start" | "side-end";
|
|
3
|
+
export type HistuiDisplayMode = "standard" | "broadcast";
|
|
3
4
|
|
|
4
5
|
export interface HistuiTheme {
|
|
5
6
|
id: string;
|
|
@@ -31,6 +32,7 @@ export interface HistuiConfig {
|
|
|
31
32
|
defaultLanguage?: string;
|
|
32
33
|
languages?: string[];
|
|
33
34
|
defaultTheme?: string;
|
|
35
|
+
displayMode?: HistuiDisplayMode;
|
|
34
36
|
orientation?: HistuiOrientation;
|
|
35
37
|
axisPlacement?: {
|
|
36
38
|
horizontal?: HistuiAxisPlacement;
|
|
@@ -83,6 +85,7 @@ export interface HistuiTimelineOptions<RecordType = any> {
|
|
|
83
85
|
theme?: HistuiTheme;
|
|
84
86
|
title?: string;
|
|
85
87
|
description?: string;
|
|
88
|
+
displayMode?: HistuiDisplayMode;
|
|
86
89
|
controls?: boolean;
|
|
87
90
|
replace?: boolean;
|
|
88
91
|
selectInitial?: boolean;
|
|
@@ -116,6 +119,7 @@ export interface HistuiState<RecordType = any> {
|
|
|
116
119
|
language: string;
|
|
117
120
|
direction: string;
|
|
118
121
|
themeId: string;
|
|
122
|
+
displayMode: HistuiDisplayMode;
|
|
119
123
|
orientation: HistuiOrientation;
|
|
120
124
|
axisPlacement: {
|
|
121
125
|
horizontal: HistuiAxisPlacement;
|
|
@@ -142,6 +146,8 @@ export class HistuiTimeline<RecordType = any> {
|
|
|
142
146
|
setExplodeEnabled(enabled: boolean): this;
|
|
143
147
|
setMeasurementOptions(options: HistuiMeasurementConfig): this;
|
|
144
148
|
setMeasurementEnabled(enabled: boolean): this;
|
|
149
|
+
setDisplayMode(displayMode: HistuiDisplayMode): this;
|
|
150
|
+
setBroadcastMode(enabled: boolean): this;
|
|
145
151
|
setLanguage(language: string, direction?: "ltr" | "rtl"): this;
|
|
146
152
|
setTheme(themeOrId: string | HistuiTheme): this;
|
|
147
153
|
applyTheme(theme: HistuiTheme): void;
|
package/src/index.js
CHANGED
|
@@ -43,6 +43,7 @@ export class HistuiTimeline {
|
|
|
43
43
|
this.direction = options.direction || dirForLanguage(this.language);
|
|
44
44
|
this.t = options.translator || makeTranslator(this.language);
|
|
45
45
|
this.themeId = options.themeId || this.config.app.defaultTheme;
|
|
46
|
+
this.displayMode = normalizeDisplayMode(options.displayMode || this.config.app.displayMode);
|
|
46
47
|
this.orientation = options.orientation || this.config.app.orientation || "auto";
|
|
47
48
|
this.axisPlacement = {
|
|
48
49
|
horizontal: options.axisPlacement?.horizontal || this.config.app.axisPlacement?.horizontal || "center",
|
|
@@ -77,6 +78,7 @@ export class HistuiTimeline {
|
|
|
77
78
|
this.root.className = "histui-timeline";
|
|
78
79
|
this.root.lang = this.language;
|
|
79
80
|
this.root.dir = this.direction;
|
|
81
|
+
this.applyDisplayMode(this.displayMode);
|
|
80
82
|
this.root.innerHTML = `
|
|
81
83
|
<section class="histui-timeline-workbench">
|
|
82
84
|
<header class="histui-timeline-head" data-histui-head></header>
|
|
@@ -269,6 +271,27 @@ export class HistuiTimeline {
|
|
|
269
271
|
return this;
|
|
270
272
|
}
|
|
271
273
|
|
|
274
|
+
setDisplayMode(displayMode) {
|
|
275
|
+
const nextMode = normalizeDisplayMode(displayMode);
|
|
276
|
+
if (nextMode === this.displayMode) return this;
|
|
277
|
+
this.displayMode = nextMode;
|
|
278
|
+
this.applyDisplayMode(nextMode);
|
|
279
|
+
this.timeline.render();
|
|
280
|
+
this.track("timeline_setting_change", { setting: "display-mode", value: nextMode });
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
setBroadcastMode(enabled) {
|
|
285
|
+
return this.setDisplayMode(enabled ? "broadcast" : "standard");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
applyDisplayMode(displayMode) {
|
|
289
|
+
if (!this.root) return;
|
|
290
|
+
const mode = normalizeDisplayMode(displayMode);
|
|
291
|
+
this.root.dataset.displayMode = mode;
|
|
292
|
+
this.root.classList.toggle("is-broadcast-mode", mode === "broadcast");
|
|
293
|
+
}
|
|
294
|
+
|
|
272
295
|
applyTheme(theme) {
|
|
273
296
|
applyTheme(theme, this.root);
|
|
274
297
|
}
|
|
@@ -285,6 +308,7 @@ export class HistuiTimeline {
|
|
|
285
308
|
language: this.language,
|
|
286
309
|
direction: this.direction,
|
|
287
310
|
themeId: this.themeId,
|
|
311
|
+
displayMode: this.displayMode,
|
|
288
312
|
orientation: this.orientation,
|
|
289
313
|
axisPlacement: { ...this.axisPlacement },
|
|
290
314
|
lodEnabled: this.lodEnabled,
|
|
@@ -459,6 +483,10 @@ function resolveContainer(container) {
|
|
|
459
483
|
return element;
|
|
460
484
|
}
|
|
461
485
|
|
|
486
|
+
function normalizeDisplayMode(displayMode) {
|
|
487
|
+
return displayMode === "broadcast" ? "broadcast" : "standard";
|
|
488
|
+
}
|
|
489
|
+
|
|
462
490
|
function mergeConfig(base, override) {
|
|
463
491
|
if (Array.isArray(base) || Array.isArray(override)) return override ?? base;
|
|
464
492
|
if (!isPlainObject(base) || !isPlainObject(override)) return override ?? base;
|
package/src/styles.css
CHANGED
|
@@ -66,6 +66,22 @@
|
|
|
66
66
|
grid-template-rows: minmax(0, 1fr) auto;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
.histui-timeline.is-broadcast-mode {
|
|
70
|
+
background: transparent;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.histui-timeline.is-broadcast-mode .histui-timeline-workbench {
|
|
74
|
+
background:
|
|
75
|
+
linear-gradient(90deg, color-mix(in srgb, var(--grid) 18%, transparent) 1px, transparent 1px),
|
|
76
|
+
linear-gradient(0deg, color-mix(in srgb, var(--grid) 14%, transparent) 1px, transparent 1px),
|
|
77
|
+
color-mix(in srgb, var(--background) 58%, transparent);
|
|
78
|
+
background-size: 52px 52px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.histui-timeline.is-broadcast-mode.has-hidden-controls .histui-timeline-workbench {
|
|
82
|
+
grid-template-rows: minmax(0, 1fr) auto;
|
|
83
|
+
}
|
|
84
|
+
|
|
69
85
|
.histui-timeline-head {
|
|
70
86
|
display: flex;
|
|
71
87
|
align-items: center;
|
|
@@ -451,6 +467,35 @@
|
|
|
451
467
|
padding: 1px 5px;
|
|
452
468
|
}
|
|
453
469
|
|
|
470
|
+
.histui-timeline.is-broadcast-mode .event-card {
|
|
471
|
+
width: 320px;
|
|
472
|
+
max-width: min(320px, calc(100vw - 42px));
|
|
473
|
+
max-height: 214px;
|
|
474
|
+
border-color: color-mix(in srgb, var(--record-color) 68%, var(--text));
|
|
475
|
+
background:
|
|
476
|
+
linear-gradient(180deg, color-mix(in srgb, var(--surface-raised) 88%, var(--record-color) 12%), color-mix(in srgb, var(--surface) 92%, transparent));
|
|
477
|
+
box-shadow:
|
|
478
|
+
0 22px 52px color-mix(in srgb, var(--shadow) 92%, transparent),
|
|
479
|
+
0 0 0 1px color-mix(in srgb, var(--record-color) 24%, transparent);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.histui-timeline.is-broadcast-mode .event-card.mode-short {
|
|
483
|
+
width: 246px;
|
|
484
|
+
max-height: 146px;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.histui-timeline.is-broadcast-mode .event-card.mode-icon {
|
|
488
|
+
width: 188px;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.histui-timeline.is-broadcast-mode .card-title {
|
|
492
|
+
font-size: 15px;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.histui-timeline.is-broadcast-mode .event-card p {
|
|
496
|
+
font-size: 13px;
|
|
497
|
+
}
|
|
498
|
+
|
|
454
499
|
.card-date {
|
|
455
500
|
display: block;
|
|
456
501
|
margin-bottom: 6px;
|
package/src/timeline-view.js
CHANGED
|
@@ -1595,7 +1595,8 @@ export class TimelineView {
|
|
|
1595
1595
|
}
|
|
1596
1596
|
|
|
1597
1597
|
if (metrics.placement === "center") {
|
|
1598
|
-
|
|
1598
|
+
const side = this.direction === "rtl" ? -1 : 1;
|
|
1599
|
+
return clamp(metrics.axisCoordinate + side * offset, 18, metrics.width - 18);
|
|
1599
1600
|
}
|
|
1600
1601
|
|
|
1601
1602
|
const side = metrics.axisCoordinate < metrics.width / 2 ? 1 : -1;
|