@terrafirmagreg-team/ui 0.1.0 → 1.2.1
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 +14 -14
- package/src/components/blocks/button/icon-button.tsx +1 -0
- package/src/components/blocks/canvas/chevron-edge.tsx +126 -18
- package/src/components/blocks/canvas/flow-canvas.tsx +4 -0
- package/src/components/blocks/canvas/flow-toolbar.tsx +1 -0
- package/src/components/blocks/canvas/flow-viewport.tsx +1 -0
- package/src/components/blocks/fit-box.tsx +26 -0
- package/src/components/blocks/git/github-info.tsx +1 -0
- package/src/components/blocks/lang/content.tsx +40 -10
- package/src/components/blocks/lang/flag.tsx +1 -0
- package/src/components/blocks/lang/link.tsx +1 -0
- package/src/components/blocks/lang/redirect.tsx +2 -1
- package/src/components/blocks/lang/switcher.tsx +1 -0
- package/src/components/blocks/lang/untranslated-callout.tsx +4 -3
- package/src/components/blocks/lang/untranslated-chip.tsx +53 -0
- package/src/components/blocks/link/link-preview.tsx +2 -1
- package/src/components/blocks/list/row.tsx +1 -0
- package/src/components/blocks/media/glb/model.tsx +1 -0
- package/src/components/blocks/media/glb/scene.tsx +13 -12
- package/src/components/blocks/media/glb/viewer.tsx +1 -0
- package/src/components/blocks/media/image.tsx +3 -2
- package/src/components/blocks/media/slideshow.tsx +4 -3
- package/src/components/blocks/nav/breadcrumb.tsx +1 -0
- package/src/components/blocks/nav/copy-menu.tsx +37 -0
- package/src/components/blocks/nav/link.tsx +1 -0
- package/src/components/blocks/nav/site-menu.tsx +1 -0
- package/src/components/blocks/nav/site-title.tsx +1 -0
- package/src/components/blocks/nav/switcher.tsx +1 -0
- package/src/components/blocks/page/empty-state.tsx +1 -0
- package/src/components/blocks/page/heading.tsx +3 -2
- package/src/components/blocks/page/pager.tsx +110 -2
- package/src/components/blocks/readability/fields.tsx +250 -0
- package/src/components/blocks/readability/menu.tsx +74 -258
- package/src/components/blocks/readability/track.tsx +2 -1
- package/src/components/blocks/search/command.tsx +1 -0
- package/src/components/blocks/search/dialog.tsx +21 -9
- package/src/components/blocks/search/provider.tsx +2 -1
- package/src/components/blocks/sidebar.tsx +5 -5
- package/src/components/blocks/sprite.tsx +231 -0
- package/src/components/blocks/text/format-text.tsx +110 -0
- package/src/components/blocks/theme/toggle.tsx +4 -0
- package/src/components/blocks/tooltip/hint.tsx +1 -0
- package/src/components/blocks/tooltip/lazy.tsx +41 -0
- package/src/components/blocks/viewer/controls.tsx +11 -6
- package/src/components/blocks/viewer/float-bar.tsx +1 -0
- package/src/components/layouts/layout.tsx +2 -1
- package/src/components/layouts/left-sidebar/content.tsx +1 -0
- package/src/components/layouts/left-sidebar/context.tsx +1 -0
- package/src/components/layouts/left-sidebar/expand.tsx +2 -1
- package/src/components/layouts/left-sidebar/footer.tsx +10 -4
- package/src/components/layouts/left-sidebar/index.ts +1 -0
- package/src/components/layouts/left-sidebar/items.tsx +2 -1
- package/src/components/layouts/left-sidebar/search.tsx +4 -3
- package/src/components/layouts/left-sidebar/sidebar.tsx +3 -2
- package/src/components/layouts/left-sidebar/tree.tsx +1 -0
- package/src/components/layouts/right-sidebar.tsx +1 -0
- package/src/components/layouts/tree-context.tsx +1 -0
- package/src/components/mdx/accordion.tsx +3 -2
- package/src/components/mdx/banner.tsx +15 -12
- package/src/components/mdx/callout.tsx +1 -0
- package/src/components/mdx/card.tsx +12 -5
- package/src/components/mdx/codeblock.tsx +5 -4
- package/src/components/mdx/collapsible.tsx +1 -0
- package/src/components/mdx/files.tsx +1 -0
- package/src/components/mdx/glow-header.tsx +17 -3
- package/src/components/mdx/gradient-text.tsx +1 -0
- package/src/components/mdx/icon.tsx +35 -0
- package/src/components/mdx/image-zoom.tsx +5 -4
- package/src/components/mdx/math.tsx +30 -0
- package/src/components/mdx/mermaid.tsx +8 -1
- package/src/components/mdx/multiblock.tsx +1 -0
- package/src/components/mdx/preview.tsx +2 -1
- package/src/components/mdx/steps.tsx +1 -0
- package/src/components/mdx/table.tsx +1 -0
- package/src/components/mdx/tabs.tsx +2 -1
- package/src/components/mdx/type-table.tsx +7 -6
- package/src/{provider.tsx → components/provider.tsx} +1 -3
- package/src/hooks/canvas/use-flow-hover.ts +1 -0
- package/src/hooks/canvas/use-flow-viewport-persist.ts +1 -0
- package/src/hooks/page/use-fit-pages.ts +1 -0
- package/src/hooks/page/use-location-search.ts +8 -2
- package/src/hooks/page/use-page-preview.ts +2 -1
- package/src/hooks/page/use-paged-list.ts +1 -0
- package/src/hooks/readability/{provider.ts → use-readability.ts} +1 -0
- package/src/hooks/search/{dialog.ts → use-dialog.ts} +1 -0
- package/src/hooks/search/use-highlight-query.ts +8 -1
- package/src/hooks/search/{provider.ts → use-provider.ts} +1 -0
- package/src/hooks/use-async-value.ts +6 -3
- package/src/hooks/use-close-on-scroll.ts +1 -0
- package/src/hooks/use-copy-button.ts +1 -0
- package/src/hooks/use-cycle-index.ts +1 -0
- package/src/hooks/use-document-title.ts +1 -0
- package/src/hooks/use-element-size.ts +1 -0
- package/src/hooks/use-external-meta.ts +2 -1
- package/src/hooks/use-hot-key.ts +1 -0
- package/src/hooks/use-hover-follow.ts +1 -0
- package/src/hooks/use-in-view.ts +1 -0
- package/src/hooks/{lang.ts → use-lang.ts} +1 -0
- package/src/hooks/use-last-value.ts +1 -0
- package/src/hooks/{layout.ts → use-layout.ts} +1 -0
- package/src/hooks/use-marquee.ts +1 -0
- package/src/hooks/use-media-query.ts +1 -0
- package/src/hooks/use-mobile.ts +1 -0
- package/src/hooks/use-modifier-keys.ts +1 -0
- package/src/hooks/use-on-change.ts +1 -0
- package/src/hooks/use-pane-keys.ts +1 -0
- package/src/hooks/{sidebar.ts → use-sidebar.ts} +1 -0
- package/src/hooks/use-swipe.ts +1 -0
- package/src/hooks/use-tree.ts +1 -3
- package/src/hooks/viewer/use-in-float-bar.ts +1 -0
- package/src/hooks/viewer/use-viewer-prefs.ts +1 -0
- package/src/lib/canvas/edge.ts +78 -49
- package/src/lib/canvas/geometry.ts +1 -0
- package/src/lib/canvas/state.ts +1 -0
- package/src/lib/canvas/viewport.ts +1 -0
- package/src/lib/canvas/xyflow.ts +1 -0
- package/src/lib/config.ts +25 -0
- package/src/lib/mdx/callout.ts +1 -0
- package/src/lib/mdx/gradient.ts +1 -0
- package/src/lib/mdx/mermaid.ts +1 -0
- package/src/lib/media/crop-opaque.ts +1 -0
- package/src/lib/media/nearby-indexes.ts +1 -0
- package/src/lib/media/trim-transparent.ts +1 -0
- package/src/lib/readability/config.ts +1 -0
- package/src/lib/readability/spotlight.ts +1 -0
- package/src/lib/readability/store.ts +1 -0
- package/src/lib/tree.ts +1 -3
- package/src/lib/utils/cn.ts +1 -0
- package/src/lib/utils/format.ts +3 -3
- package/src/lib/utils/highlight-style.ts +10 -0
- package/src/lib/utils/history.ts +1 -0
- package/src/lib/utils/merge-refs.ts +1 -0
- package/src/lib/utils/nav-active.ts +1 -0
- package/src/lib/utils/stored-value.ts +1 -0
- package/src/lib/utils/urls.ts +2 -1
- package/src/locales/en_us.json +108 -117
- package/src/locales/pl_pl.json +33 -35
- package/src/locales/ru_ru.json +108 -117
- package/src/locales/uk_ua.json +33 -35
- package/src/locales/zh_cn.json +15 -17
- package/src/locales/zh_tw.json +15 -17
- package/src/locales.ts +1 -0
- package/src/types/canvas.ts +6 -1
- package/src/types/glb.ts +1 -0
- package/src/types/mdx-directives.ts +106 -0
- package/src/types/nav.ts +1 -0
- package/src/types/preview.ts +7 -1
- package/src/types/readability.ts +1 -0
- package/src/types/search.ts +1 -0
- package/src/types/tree.ts +1 -0
- package/src/types/viewer.ts +1 -0
- package/styles/content/base.css +198 -194
- package/styles/content/shiki.css +107 -108
- package/styles/content/typography.mjs +3637 -3941
- package/styles/content.css +5 -7
- package/styles.css +430 -413
- package/src/lib/utils/async-cache.ts +0 -32
package/src/hooks/use-marquee.ts
CHANGED
package/src/hooks/use-mobile.ts
CHANGED
package/src/hooks/use-swipe.ts
CHANGED
package/src/hooks/use-tree.ts
CHANGED
|
@@ -18,7 +18,6 @@ export function useTreeContext(): TreeContextValue {
|
|
|
18
18
|
return ctx;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
21
|
export function useTabsGroups(tabs: TabOption[]): {
|
|
23
22
|
active?: PageTree.Folder;
|
|
24
23
|
options: TabOption[];
|
|
@@ -52,7 +51,6 @@ export function useTabsGroups(tabs: TabOption[]): {
|
|
|
52
51
|
}, [tabs, tree, path]);
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
|
|
56
54
|
function collectTabs(
|
|
57
55
|
scope: PageTree.Node[],
|
|
58
56
|
active: PageTree.Folder,
|
|
@@ -80,7 +78,6 @@ function collectTabs(
|
|
|
80
78
|
|
|
81
79
|
const footerCache = new WeakMap<PageTree.Root | PageTree.Folder, PageTree.Item[]>();
|
|
82
80
|
|
|
83
|
-
|
|
84
81
|
export function useFooterItems(): PageTree.Item[] {
|
|
85
82
|
const { root } = useTreeContext();
|
|
86
83
|
const cached = footerCache.get(root);
|
|
@@ -100,3 +97,4 @@ export function useFooterItems(): PageTree.Item[] {
|
|
|
100
97
|
footerCache.set(root, list);
|
|
101
98
|
return list;
|
|
102
99
|
}
|
|
100
|
+
|
package/src/lib/canvas/edge.ts
CHANGED
|
@@ -3,65 +3,31 @@ import type {
|
|
|
3
3
|
FlowPoint,
|
|
4
4
|
} from '@terrafirmagreg-team/ui/types/canvas';
|
|
5
5
|
|
|
6
|
-
const CHEVRON_SPACING = 10;
|
|
6
|
+
export const CHEVRON_SPACING = 10;
|
|
7
7
|
const CHEVRON_SIZE = 3.5;
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
export const CHEVRON_GLYPH = `M${-CHEVRON_SIZE * 0.45} ${-CHEVRON_SIZE * 0.9}L${CHEVRON_SIZE} 0L${-CHEVRON_SIZE * 0.45} ${CHEVRON_SIZE * 0.9}`;
|
|
10
10
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
): ChevronRun[] {
|
|
16
|
-
if (points.length < 2) return [];
|
|
17
|
-
const lens: number[] = [];
|
|
11
|
+
export function chevronTicksAlongPath(points: readonly FlowPoint[]): {
|
|
12
|
+
offsets: number[];
|
|
13
|
+
total: number;
|
|
14
|
+
} {
|
|
18
15
|
let total = 0;
|
|
19
16
|
for (let i = 0; i + 1 < points.length; i += 1) {
|
|
20
|
-
|
|
17
|
+
total += Math.hypot(
|
|
21
18
|
points[i + 1]!.x - points[i]!.x,
|
|
22
19
|
points[i + 1]!.y - points[i]!.y,
|
|
23
20
|
);
|
|
24
|
-
lens.push(len);
|
|
25
|
-
total += len;
|
|
26
21
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
let segStart = 0;
|
|
35
|
-
for (let d = CHEVRON_SPACING; d <= total; d += CHEVRON_SPACING) {
|
|
36
|
-
while (seg < lens.length && segStart + lens[seg]! < d) {
|
|
37
|
-
segStart += lens[seg]!;
|
|
38
|
-
seg += 1;
|
|
39
|
-
}
|
|
40
|
-
if (seg >= lens.length) break;
|
|
41
|
-
const len = lens[seg]!;
|
|
42
|
-
if (len < 0.001) continue;
|
|
43
|
-
const p0 = points[seg]!;
|
|
44
|
-
const p1 = points[seg + 1]!;
|
|
45
|
-
const t = (d - segStart) / len;
|
|
46
|
-
const ux = (p1.x - p0.x) / len;
|
|
47
|
-
const uy = (p1.y - p0.y) / len;
|
|
48
|
-
const cx = p0.x + (p1.x - p0.x) * t;
|
|
49
|
-
const cy = p0.y + (p1.y - p0.y) * t;
|
|
50
|
-
if (!run || ux * run.ux + uy * run.uy < RUN_COS) {
|
|
51
|
-
run = { ux, uy, parts: [] };
|
|
52
|
-
runs.push(run);
|
|
53
|
-
}
|
|
54
|
-
const px = -uy;
|
|
55
|
-
const py = ux;
|
|
56
|
-
run.parts.push(
|
|
57
|
-
`M${cx - ux * back + px * wing} ${cy - uy * back + py * wing}L${cx + ux * size} ${cy + uy * size}L${cx - ux * back - px * wing} ${cy - uy * back - py * wing}`,
|
|
58
|
-
);
|
|
22
|
+
const offsets: number[] = [];
|
|
23
|
+
for (
|
|
24
|
+
let d = CHEVRON_SPACING;
|
|
25
|
+
d <= total - CHEVRON_SPACING / 2;
|
|
26
|
+
d += CHEVRON_SPACING
|
|
27
|
+
) {
|
|
28
|
+
offsets.push(d);
|
|
59
29
|
}
|
|
60
|
-
return
|
|
61
|
-
d: entry.parts.join(''),
|
|
62
|
-
shiftX: entry.ux * CHEVRON_SPACING,
|
|
63
|
-
shiftY: entry.uy * CHEVRON_SPACING,
|
|
64
|
-
}));
|
|
30
|
+
return { offsets, total };
|
|
65
31
|
}
|
|
66
32
|
|
|
67
33
|
export function svgPathToPoints(d: string, samples = 12): FlowPoint[] {
|
|
@@ -155,6 +121,66 @@ export function chamferedPolylinePath(
|
|
|
155
121
|
return `${d}L${last.x} ${last.y}`;
|
|
156
122
|
}
|
|
157
123
|
|
|
124
|
+
export function roundedPolylinePath(
|
|
125
|
+
points: readonly FlowPoint[],
|
|
126
|
+
radius = 10,
|
|
127
|
+
): string {
|
|
128
|
+
if (!points.length) return '';
|
|
129
|
+
if (points.length < 3) {
|
|
130
|
+
return `M${points[0]!.x} ${points[0]!.y}${points
|
|
131
|
+
.slice(1)
|
|
132
|
+
.map((p) => `L${p.x} ${p.y}`)
|
|
133
|
+
.join('')}`;
|
|
134
|
+
}
|
|
135
|
+
let d = `M${points[0]!.x} ${points[0]!.y}`;
|
|
136
|
+
let cursor = points[0]!;
|
|
137
|
+
for (let i = 1; i + 1 < points.length; i += 1) {
|
|
138
|
+
const corner = points[i]!;
|
|
139
|
+
const next = points[i + 1]!;
|
|
140
|
+
const inLen = Math.hypot(corner.x - cursor.x, corner.y - cursor.y);
|
|
141
|
+
const outLen = Math.hypot(next.x - corner.x, next.y - corner.y);
|
|
142
|
+
const take = Math.min(radius, inLen / 2, outLen / 2);
|
|
143
|
+
if (take < 0.5) {
|
|
144
|
+
d += `L${corner.x} ${corner.y}`;
|
|
145
|
+
cursor = corner;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const ax = corner.x - ((corner.x - cursor.x) / inLen) * take;
|
|
149
|
+
const ay = corner.y - ((corner.y - cursor.y) / inLen) * take;
|
|
150
|
+
const bx = corner.x + ((next.x - corner.x) / outLen) * take;
|
|
151
|
+
const by = corner.y + ((next.y - corner.y) / outLen) * take;
|
|
152
|
+
d += `L${ax} ${ay}Q${corner.x} ${corner.y} ${bx} ${by}`;
|
|
153
|
+
cursor = { x: bx, y: by };
|
|
154
|
+
}
|
|
155
|
+
const last = points[points.length - 1]!;
|
|
156
|
+
return `${d}L${last.x} ${last.y}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function nearestPointOnPolyline(
|
|
160
|
+
points: readonly FlowPoint[],
|
|
161
|
+
p: FlowPoint,
|
|
162
|
+
): FlowPoint {
|
|
163
|
+
let best = points[0]!;
|
|
164
|
+
let bestD = Infinity;
|
|
165
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
166
|
+
const a = points[i - 1]!;
|
|
167
|
+
const b = points[i]!;
|
|
168
|
+
const dx = b.x - a.x;
|
|
169
|
+
const dy = b.y - a.y;
|
|
170
|
+
const len2 = dx * dx + dy * dy;
|
|
171
|
+
const t = len2
|
|
172
|
+
? Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2))
|
|
173
|
+
: 0;
|
|
174
|
+
const q = { x: a.x + dx * t, y: a.y + dy * t };
|
|
175
|
+
const d = (q.x - p.x) ** 2 + (q.y - p.y) ** 2;
|
|
176
|
+
if (d < bestD) {
|
|
177
|
+
bestD = d;
|
|
178
|
+
best = q;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return best;
|
|
182
|
+
}
|
|
183
|
+
|
|
158
184
|
export function chevronHighlightClass(
|
|
159
185
|
highlight: ChevronEdgeHighlight,
|
|
160
186
|
): string {
|
|
@@ -163,6 +189,8 @@ export function chevronHighlightClass(
|
|
|
163
189
|
return 'chevron-edge--incoming';
|
|
164
190
|
case 'outgoing':
|
|
165
191
|
return 'chevron-edge--outgoing';
|
|
192
|
+
case 'dim':
|
|
193
|
+
return 'chevron-edge--dim';
|
|
166
194
|
case undefined:
|
|
167
195
|
return '';
|
|
168
196
|
default: {
|
|
@@ -171,3 +199,4 @@ export function chevronHighlightClass(
|
|
|
171
199
|
}
|
|
172
200
|
}
|
|
173
201
|
}
|
|
202
|
+
|
package/src/lib/canvas/state.ts
CHANGED
package/src/lib/canvas/xyflow.ts
CHANGED
package/src/lib/config.ts
CHANGED
|
@@ -22,6 +22,22 @@ export const DEFAULT_EXTERNAL_META_PROVIDERS: ExternalMetaProvider[] = [
|
|
|
22
22
|
description: 'description',
|
|
23
23
|
replace: [[/_/g, ' ']],
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
host: /^github\.com$/i,
|
|
27
|
+
path: /^\/([^/]+)\/([^/?#]+)\/releases\/tag\/([^/?#]+)\/?$/,
|
|
28
|
+
url: 'https://api.github.com/repos/{1}/{2}/releases/tags/{3}',
|
|
29
|
+
kind: 'json',
|
|
30
|
+
title: 'name',
|
|
31
|
+
description: 'body',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
host: /^github\.com$/i,
|
|
35
|
+
path: /^\/([^/]+)\/([^/?#]+)\/(?:issues|pull)\/([^/?#]+)\/?$/,
|
|
36
|
+
url: 'https://api.github.com/repos/{1}/{2}/issues/{3}',
|
|
37
|
+
kind: 'json',
|
|
38
|
+
title: 'title',
|
|
39
|
+
description: 'body',
|
|
40
|
+
},
|
|
25
41
|
{
|
|
26
42
|
host: /^github\.com$/i,
|
|
27
43
|
path: /^\/([^/]+)\/([^/?#]+)\/?$/,
|
|
@@ -30,6 +46,14 @@ export const DEFAULT_EXTERNAL_META_PROVIDERS: ExternalMetaProvider[] = [
|
|
|
30
46
|
title: 'full_name',
|
|
31
47
|
description: 'description',
|
|
32
48
|
},
|
|
49
|
+
{
|
|
50
|
+
host: /^github\.com$/i,
|
|
51
|
+
path: /^\/([^/?#]+)\/?$/,
|
|
52
|
+
url: 'https://api.github.com/users/{1}',
|
|
53
|
+
kind: 'json',
|
|
54
|
+
title: 'name',
|
|
55
|
+
description: 'bio',
|
|
56
|
+
},
|
|
33
57
|
{
|
|
34
58
|
host: /.*/,
|
|
35
59
|
url: 'https://api.allorigins.win/raw?url={href}',
|
|
@@ -79,3 +103,4 @@ const { register: registerUiConfig, get: uiConfig } =
|
|
|
79
103
|
createConfigRegistry<UiConfig>();
|
|
80
104
|
|
|
81
105
|
export { registerUiConfig, uiConfig };
|
|
106
|
+
|
package/src/lib/mdx/callout.ts
CHANGED
package/src/lib/mdx/gradient.ts
CHANGED
package/src/lib/mdx/mermaid.ts
CHANGED
package/src/lib/tree.ts
CHANGED
|
@@ -7,7 +7,6 @@ export function normalizeUrl(url: string): string {
|
|
|
7
7
|
return url;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
export function findPath(
|
|
12
11
|
nodes: PageTree.Node[],
|
|
13
12
|
matcher: (node: PageTree.Node) => boolean,
|
|
@@ -45,7 +44,6 @@ export function findPath(
|
|
|
45
44
|
return run(nodes) ?? null;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
|
|
49
47
|
export function searchPath(
|
|
50
48
|
nodes: PageTree.Node[],
|
|
51
49
|
url: string,
|
|
@@ -57,7 +55,6 @@ export function searchPath(
|
|
|
57
55
|
);
|
|
58
56
|
}
|
|
59
57
|
|
|
60
|
-
|
|
61
58
|
export function findProjection(
|
|
62
59
|
from: PageTree.Folder,
|
|
63
60
|
to: PageTree.Folder,
|
|
@@ -90,3 +87,4 @@ export function findProjection(
|
|
|
90
87
|
}
|
|
91
88
|
return projection;
|
|
92
89
|
}
|
|
90
|
+
|
package/src/lib/utils/cn.ts
CHANGED
package/src/lib/utils/format.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export function formatCount(value: number): string {
|
|
1
|
+
export function formatCount(value: number, roundAt = 10_000): string {
|
|
3
2
|
if (!Number.isFinite(value)) return String(value);
|
|
4
3
|
const abs = Math.abs(value);
|
|
5
|
-
if (abs <
|
|
4
|
+
if (abs < roundAt) return String(Math.trunc(value));
|
|
6
5
|
const units: [number, string][] = [
|
|
7
6
|
[1_000_000_000, 'B'],
|
|
8
7
|
[1_000_000, 'M'],
|
|
@@ -20,3 +19,4 @@ export function formatCount(value: number): string {
|
|
|
20
19
|
}
|
|
21
20
|
return String(value);
|
|
22
21
|
}
|
|
22
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const injected = new Set<string>();
|
|
2
|
+
|
|
3
|
+
export function injectHighlightStyle(name: string, css: string): void {
|
|
4
|
+
if (injected.has(name) || typeof document === 'undefined') return;
|
|
5
|
+
injected.add(name);
|
|
6
|
+
const style = document.createElement('style');
|
|
7
|
+
style.textContent = `::highlight(${name}){${css}}`;
|
|
8
|
+
document.head.appendChild(style);
|
|
9
|
+
}
|
|
10
|
+
|
package/src/lib/utils/history.ts
CHANGED
package/src/lib/utils/urls.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function safeURL(value?: string): string | undefined {
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
if (!value || /[\u0000-\u0020\\]/.test(value)) return undefined;
|
|
4
4
|
return /^(https?:\/\/|\/(?!\/)|#)/i.test(value) ? value : undefined;
|
|
5
5
|
}
|
|
@@ -15,3 +15,4 @@ export function isActive(href: string, pathname: string, nested = false): boolea
|
|
|
15
15
|
|
|
16
16
|
return href === pathname || (nested && pathname.startsWith(`${href}/`));
|
|
17
17
|
}
|
|
18
|
+
|