@trebired/git-host 1.4.0 → 1.6.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.
@@ -0,0 +1,733 @@
1
+ import { createElement, useEffect, useState, } from "react";
2
+ import { applyGitStarOptimisticState, applyGitWatchOptimisticState, useGitBranches, useGitCreateFork, useGitCreateRelease, useGitDeleteRelease, useGitSocialState, useGitStarRepository, useGitSyncFork, useGitTags, useGitUnstarRepository, useGitUnwatchRepository, useGitWatchRepository, } from "./hooks.js";
3
+ import { GitRepositoryUiProvider, resolveGitRepositorySlotProps, useGitRepositoryClassName, useGitRepositoryDiagnostics, useGitRepositoryRouteAdapter, useGitRepositoryUi, } from "./ui/context.js";
4
+ import { text } from "../utils/text.js";
5
+ const h = createElement;
6
+ function joinClassNames(...values) {
7
+ return values.filter(Boolean).join(" ");
8
+ }
9
+ function formatDate(value) {
10
+ const next = text(value);
11
+ if (!next)
12
+ return "Unknown";
13
+ try {
14
+ return new Date(next).toLocaleString("en-US", {
15
+ dateStyle: "medium",
16
+ timeStyle: "short",
17
+ });
18
+ }
19
+ catch {
20
+ return next;
21
+ }
22
+ }
23
+ function useGitRepositorySlots() {
24
+ const ui = useGitRepositoryUi();
25
+ return (slot, input = {}) => resolveGitRepositorySlotProps(ui, slot, input);
26
+ }
27
+ function useGitRepositoryRenderState(page, repositoryKey, input) {
28
+ const diagnostics = useGitRepositoryDiagnostics();
29
+ useEffect(() => {
30
+ diagnostics.onViewMount?.({ page, repositoryKey });
31
+ }, [diagnostics, page, repositoryKey]);
32
+ useEffect(() => {
33
+ diagnostics.onRenderStateChange?.({
34
+ empty: input.empty === true,
35
+ error: Boolean(input.error),
36
+ loading: input.loading === true,
37
+ page,
38
+ repositoryKey,
39
+ });
40
+ if (input.empty === true) {
41
+ diagnostics.onEmptyState?.({
42
+ page,
43
+ reason: text(input.emptyReason, "empty"),
44
+ repositoryKey,
45
+ });
46
+ }
47
+ }, [diagnostics, input.empty, input.emptyReason, input.error, input.loading, page, repositoryKey]);
48
+ }
49
+ function GitLoadingState(props) {
50
+ const ui = useGitRepositoryUi();
51
+ const slot = useGitRepositorySlots();
52
+ const Override = ui.components.LoadingState;
53
+ if (Override)
54
+ return h(Override, props);
55
+ return h("div", slot("loading-state", {
56
+ className: useGitRepositoryClassName("status", props.className),
57
+ children: props.message || "Loading repository data...",
58
+ }));
59
+ }
60
+ function GitErrorState(props) {
61
+ const ui = useGitRepositoryUi();
62
+ const slot = useGitRepositorySlots();
63
+ const Override = ui.components.ErrorState;
64
+ if (Override)
65
+ return h(Override, props);
66
+ return h("div", slot("error-state", {
67
+ className: useGitRepositoryClassName("status", "is-error", props.className),
68
+ children: [
69
+ h("div", { key: "message", children: props.error?.message || "This repository view failed to load." }),
70
+ props.onRetry
71
+ ? h("button", {
72
+ ...slot("button", {}),
73
+ key: "retry",
74
+ onClick: props.onRetry,
75
+ type: "button",
76
+ children: "Retry",
77
+ })
78
+ : null,
79
+ ],
80
+ }));
81
+ }
82
+ function GitEmptyState(props) {
83
+ const ui = useGitRepositoryUi();
84
+ const slot = useGitRepositorySlots();
85
+ const Override = ui.components.EmptyState;
86
+ if (Override)
87
+ return h(Override, props);
88
+ return h("section", slot("empty-state", {
89
+ className: props.className,
90
+ children: [
91
+ h("h3", slot("empty-title", { key: "title", children: props.title || "Nothing here yet" })),
92
+ h("p", slot("note", { key: "message", children: props.message || "This repository section is empty." })),
93
+ props.action ? h("div", slot("empty-action", { key: "action", children: props.action })) : null,
94
+ ],
95
+ }));
96
+ }
97
+ function GitRepositoryTabs(props) {
98
+ const ui = useGitRepositoryUi();
99
+ const slot = useGitRepositorySlots();
100
+ const routes = useGitRepositoryRouteAdapter();
101
+ const activeClassName = useGitRepositoryClassName("button-active");
102
+ const items = [
103
+ { key: "overview", label: "Overview", to: routes.overview(props.repositoryKey) },
104
+ { key: "code", label: "Code", to: routes.code(props.repositoryKey) },
105
+ { key: "commits", label: "Commits", to: routes.commits(props.repositoryKey) },
106
+ { key: "branches", label: "Branches", to: routes.branches(props.repositoryKey) },
107
+ { key: "tags", label: "Tags", to: routes.tags(props.repositoryKey) },
108
+ { key: "releases", label: "Releases", to: routes.releases(props.repositoryKey) },
109
+ { key: "forks", label: "Forks", to: routes.forks(props.repositoryKey) },
110
+ { key: "activity", label: "Activity", to: routes.activity(props.repositoryKey) },
111
+ { key: "search", label: "Search", to: routes.search(props.repositoryKey) },
112
+ ];
113
+ return h("nav", slot("tabs", {
114
+ className: props.className,
115
+ children: items.map((item) => h("button", {
116
+ ...slot("tab-link", {
117
+ className: item.key === props.active ? activeClassName : undefined,
118
+ }),
119
+ key: item.key,
120
+ onClick: () => ui.navigate(item.to),
121
+ type: "button",
122
+ children: item.label,
123
+ })),
124
+ }));
125
+ }
126
+ function GitRepositoryStats(props) {
127
+ const slot = useGitRepositorySlots();
128
+ return h("dl", slot("stats", {
129
+ className: useGitRepositoryClassName("definition-grid", props.className),
130
+ children: props.stats.flatMap((entry) => ([
131
+ h("dt", { key: `${entry.label}:label`, children: entry.label }),
132
+ h("dd", { key: `${entry.label}:value`, children: entry.value }),
133
+ ])),
134
+ }));
135
+ }
136
+ function GitStarButton(props) {
137
+ const [optimistic, setOptimistic] = useState(props.social || null);
138
+ const slot = useGitRepositorySlots();
139
+ const activeClassName = useGitRepositoryClassName("button-active");
140
+ const star = useGitStarRepository(props.repositoryKey, { headers: props.headers });
141
+ const unstar = useGitUnstarRepository(props.repositoryKey, { headers: props.headers });
142
+ useEffect(() => {
143
+ setOptimistic(props.social || null);
144
+ }, [props.social]);
145
+ return h("button", {
146
+ ...slot("button", {
147
+ className: optimistic?.viewer_has_starred ? activeClassName : undefined,
148
+ }),
149
+ disabled: star.loading || unstar.loading,
150
+ onClick: async () => {
151
+ const next = optimistic?.viewer_has_starred !== true;
152
+ setOptimistic(applyGitStarOptimisticState(optimistic, next));
153
+ try {
154
+ setOptimistic(next ? await star.mutate() : await unstar.mutate());
155
+ }
156
+ catch {
157
+ setOptimistic(props.social || null);
158
+ }
159
+ },
160
+ type: "button",
161
+ children: `${optimistic?.viewer_has_starred ? "Starred" : "Star"} ${optimistic?.star_count ?? 0}`,
162
+ });
163
+ }
164
+ function GitWatchButton(props) {
165
+ const [optimistic, setOptimistic] = useState(props.social || null);
166
+ const slot = useGitRepositorySlots();
167
+ const activeClassName = useGitRepositoryClassName("button-active");
168
+ const watch = useGitWatchRepository(props.repositoryKey, { headers: props.headers });
169
+ const unwatch = useGitUnwatchRepository(props.repositoryKey, { headers: props.headers });
170
+ useEffect(() => {
171
+ setOptimistic(props.social || null);
172
+ }, [props.social]);
173
+ return h("button", {
174
+ ...slot("button", {
175
+ className: optimistic?.viewer_is_watching ? activeClassName : undefined,
176
+ }),
177
+ disabled: watch.loading || unwatch.loading,
178
+ onClick: async () => {
179
+ const next = optimistic?.viewer_is_watching !== true;
180
+ setOptimistic(applyGitWatchOptimisticState(optimistic, next));
181
+ try {
182
+ setOptimistic(next ? await watch.mutate() : await unwatch.mutate());
183
+ }
184
+ catch {
185
+ setOptimistic(props.social || null);
186
+ }
187
+ },
188
+ type: "button",
189
+ children: `${optimistic?.viewer_is_watching ? "Watching" : "Watch"} ${optimistic?.watcher_count ?? 0}`,
190
+ });
191
+ }
192
+ function GitForkButton(props) {
193
+ const mutation = useGitCreateFork(props.repositoryKey, { headers: props.headers });
194
+ const slot = useGitRepositorySlots();
195
+ return h("button", {
196
+ ...slot("button", {
197
+ className: useGitRepositoryClassName("button-primary"),
198
+ }),
199
+ disabled: mutation.loading,
200
+ onClick: async () => {
201
+ const created = await mutation.mutate();
202
+ props.onCreated?.(created);
203
+ },
204
+ type: "button",
205
+ children: mutation.loading ? "Forking..." : "Create Fork",
206
+ });
207
+ }
208
+ function GitSyncForkButton(props) {
209
+ const mutation = useGitSyncFork(props.repositoryKey, props.forkId, { headers: props.headers });
210
+ const slot = useGitRepositorySlots();
211
+ return h("button", {
212
+ ...slot("button", {}),
213
+ disabled: mutation.loading,
214
+ onClick: async () => {
215
+ const synced = await mutation.mutate({ strategy: "ff-only" });
216
+ props.onSynced?.(synced);
217
+ },
218
+ type: "button",
219
+ children: mutation.loading ? "Syncing..." : "Sync Fork",
220
+ });
221
+ }
222
+ function GitCreateReleaseButton(props) {
223
+ const mutation = useGitCreateRelease(props.repositoryKey, { headers: props.headers });
224
+ const slot = useGitRepositorySlots();
225
+ return h("button", {
226
+ ...slot("button", {
227
+ className: useGitRepositoryClassName("button-primary"),
228
+ }),
229
+ disabled: mutation.loading,
230
+ onClick: async () => {
231
+ const release = await mutation.mutate(props.input);
232
+ props.onCreated?.(release);
233
+ },
234
+ type: "button",
235
+ children: mutation.loading ? "Publishing..." : "Create Release",
236
+ });
237
+ }
238
+ function GitEditReleaseButton(props) {
239
+ const slot = useGitRepositorySlots();
240
+ return h("button", {
241
+ ...slot("button", {}),
242
+ disabled: props.disabled,
243
+ onClick: props.onClick,
244
+ type: "button",
245
+ children: "Edit Release",
246
+ });
247
+ }
248
+ function GitDeleteReleaseButton(props) {
249
+ const mutation = useGitDeleteRelease(props.repositoryKey, props.releaseId, { headers: props.headers });
250
+ const slot = useGitRepositorySlots();
251
+ return h("button", {
252
+ ...slot("button", {}),
253
+ disabled: mutation.loading,
254
+ onClick: async () => {
255
+ await mutation.mutate({ deleteTag: props.deleteTag });
256
+ props.onDeleted?.();
257
+ },
258
+ type: "button",
259
+ children: mutation.loading ? "Deleting..." : "Delete Release",
260
+ });
261
+ }
262
+ function GitRepositorySocialButtons(props) {
263
+ const social = useGitSocialState(props.repositoryKey, {
264
+ headers: props.headers,
265
+ initialData: props.social || null,
266
+ });
267
+ const slot = useGitRepositorySlots();
268
+ return h("div", {
269
+ ...slot("actions", {}),
270
+ children: [
271
+ h(GitStarButton, { headers: props.headers, key: "star", repositoryKey: props.repositoryKey, social: social.data }),
272
+ h(GitWatchButton, { headers: props.headers, key: "watch", repositoryKey: props.repositoryKey, social: social.data }),
273
+ ],
274
+ });
275
+ }
276
+ function GitBranchSelector(props) {
277
+ const branches = useGitBranches(props.repositoryKey, { headers: props.headers });
278
+ const ui = useGitRepositoryUi();
279
+ const slot = useGitRepositorySlots();
280
+ const routes = useGitRepositoryRouteAdapter();
281
+ return h("select", {
282
+ ...slot("input", { className: props.className }),
283
+ disabled: branches.loading,
284
+ onChange: (event) => {
285
+ const branch = text(event.target?.value);
286
+ props.onSelect?.(branch);
287
+ if (branch)
288
+ ui.navigate(routes.code(props.repositoryKey, "", branch));
289
+ },
290
+ value: props.selectedBranch || "",
291
+ children: [
292
+ h("option", { key: "empty", value: "", children: branches.loading ? "Loading branches..." : "Branch switcher" }),
293
+ ...(branches.data || []).map((branch) => h("option", {
294
+ key: branch.name,
295
+ value: branch.name,
296
+ children: branch.current ? `${branch.name} (current)` : branch.name,
297
+ })),
298
+ ],
299
+ });
300
+ }
301
+ function GitTagSelector(props) {
302
+ const tags = useGitTags(props.repositoryKey, { headers: props.headers });
303
+ const ui = useGitRepositoryUi();
304
+ const slot = useGitRepositorySlots();
305
+ const routes = useGitRepositoryRouteAdapter();
306
+ return h("select", {
307
+ ...slot("input", { className: props.className }),
308
+ disabled: tags.loading,
309
+ onChange: (event) => {
310
+ const tag = text(event.target?.value);
311
+ props.onSelect?.(tag);
312
+ if (tag)
313
+ ui.navigate(routes.code(props.repositoryKey, "", tag));
314
+ },
315
+ value: props.selectedTag || "",
316
+ children: [
317
+ h("option", { key: "empty", value: "", children: tags.loading ? "Loading tags..." : "Tag selector" }),
318
+ ...(tags.data || []).map((tag) => h("option", {
319
+ key: tag.name,
320
+ value: tag.name,
321
+ children: tag.name,
322
+ })),
323
+ ],
324
+ });
325
+ }
326
+ function GitDownloadArchiveButton(props) {
327
+ const ui = useGitRepositoryUi();
328
+ const slot = useGitRepositorySlots();
329
+ const href = ui.client
330
+ ? `${ui.client.baseUrl}/repositories/${encodeURIComponent(props.repositoryKey)}/archive?format=${encodeURIComponent(props.format || "zip")}${props.refName ? `&ref=${encodeURIComponent(props.refName)}` : ""}`
331
+ : undefined;
332
+ return h("a", {
333
+ ...slot("button", {}),
334
+ href,
335
+ children: "Download Archive",
336
+ });
337
+ }
338
+ function GitCopyCloneUrlButton(props) {
339
+ const ui = useGitRepositoryUi();
340
+ const slot = useGitRepositorySlots();
341
+ const value = ui.branding.getCloneUrl?.(props.repositoryKey, props.protocol || "http") || "";
342
+ return h("button", {
343
+ ...slot("button", {}),
344
+ disabled: !value,
345
+ onClick: async () => {
346
+ try {
347
+ const clipboard = globalThis.navigator?.clipboard;
348
+ if (value && clipboard?.writeText)
349
+ await clipboard.writeText(value);
350
+ }
351
+ catch { }
352
+ },
353
+ type: "button",
354
+ children: "Copy Clone URL",
355
+ });
356
+ }
357
+ function GitRepositoryActionBar(props) {
358
+ const slot = useGitRepositorySlots();
359
+ return h("div", slot("action-bar", {
360
+ className: props.className,
361
+ children: props.children,
362
+ }));
363
+ }
364
+ function GitPathBreadcrumbs(props) {
365
+ const ui = useGitRepositoryUi();
366
+ const slot = useGitRepositorySlots();
367
+ const routes = useGitRepositoryRouteAdapter();
368
+ const parts = text(props.path).split("/").filter(Boolean);
369
+ let current = "";
370
+ return h("div", {
371
+ ...slot("breadcrumbs", {}),
372
+ children: [
373
+ h("button", {
374
+ ...slot("breadcrumb", {}),
375
+ key: "root",
376
+ onClick: () => ui.navigate(routes.code(props.repositoryKey, "", props.refName)),
377
+ type: "button",
378
+ children: props.refName || "root",
379
+ }),
380
+ ...parts.map((part, index) => {
381
+ current = current ? `${current}/${part}` : part;
382
+ return h("button", {
383
+ ...slot("breadcrumb", {}),
384
+ key: `${part}:${index}`,
385
+ onClick: () => ui.navigate(routes.code(props.repositoryKey, current, props.refName)),
386
+ type: "button",
387
+ children: part,
388
+ });
389
+ }),
390
+ ],
391
+ });
392
+ }
393
+ function GitRepositoryHeader(props) {
394
+ const ui = useGitRepositoryUi();
395
+ const slot = useGitRepositorySlots();
396
+ return h("section", slot("header", {
397
+ className: joinClassNames(props.className, ui.theme.className),
398
+ style: ui.themeStyle,
399
+ children: [
400
+ h("div", slot("header-top", {
401
+ key: "title",
402
+ children: [
403
+ h("div", slot("title-block", {
404
+ key: "block",
405
+ children: [
406
+ h("div", slot("badge", { key: "badge", children: "Embeddable Forge UI" })),
407
+ h("h1", slot("title", {
408
+ className: ui.theme.typography?.headingClassName,
409
+ key: "title",
410
+ children: props.title || props.repositoryKey,
411
+ })),
412
+ h("p", slot("subtitle", {
413
+ className: ui.theme.typography?.bodyClassName,
414
+ key: "subtitle",
415
+ children: props.subtitle || (typeof ui.branding.subtitle === "string" ? ui.branding.subtitle : "Repository workspace"),
416
+ })),
417
+ ],
418
+ })),
419
+ props.actions ? h("div", slot("header-actions", { key: "actions", children: props.actions })) : null,
420
+ ],
421
+ })),
422
+ props.stats?.length ? h(GitRepositoryStats, {
423
+ key: "stats",
424
+ repositoryKey: props.repositoryKey,
425
+ social: props.social,
426
+ stats: props.stats,
427
+ }) : null,
428
+ h(GitRepositoryTabs, {
429
+ active: props.page,
430
+ key: "tabs",
431
+ repositoryKey: props.repositoryKey,
432
+ }),
433
+ ],
434
+ }));
435
+ }
436
+ function GitRepositoryShell(props) {
437
+ useGitRepositoryRenderState(props.page, props.repositoryKey, {
438
+ empty: props.empty,
439
+ error: props.error,
440
+ loading: props.loading,
441
+ });
442
+ const slot = useGitRepositorySlots();
443
+ return h("div", slot("page", {
444
+ className: props.className,
445
+ children: [
446
+ h(GitRepositoryHeader, {
447
+ actions: props.actions,
448
+ key: "header",
449
+ page: props.page,
450
+ repositoryKey: props.repositoryKey,
451
+ social: props.social,
452
+ stats: props.stats,
453
+ subtitle: props.subtitle,
454
+ title: props.title,
455
+ }),
456
+ props.loading
457
+ ? h(GitLoadingState, { key: "loading" })
458
+ : props.error
459
+ ? h(GitErrorState, { error: props.error, key: "error", onRetry: props.retry })
460
+ : props.empty
461
+ ? (props.emptyState || h(GitEmptyState, { key: "empty" }))
462
+ : h("div", slot("shell-body", { key: "body", children: props.children })),
463
+ ],
464
+ }));
465
+ }
466
+ function GitCommitList(props) {
467
+ const ui = useGitRepositoryUi();
468
+ const slot = useGitRepositorySlots();
469
+ const routes = useGitRepositoryRouteAdapter();
470
+ if (!props.commits.length) {
471
+ return h(GitEmptyState, { message: props.emptyMessage || "No commits matched this repository view." });
472
+ }
473
+ return h("ul", {
474
+ ...slot("list", {}),
475
+ children: props.commits.map((commit) => h("li", {
476
+ ...slot("list-item", {}),
477
+ key: commit.hash,
478
+ children: [
479
+ h("button", {
480
+ ...slot("list-link", {}),
481
+ key: "subject",
482
+ onClick: () => ui.navigate(routes.commit(props.repositoryKey, commit.hash)),
483
+ type: "button",
484
+ children: `${commit.short_hash} · ${commit.subject}`,
485
+ }),
486
+ h("div", slot("note", { key: "meta", children: `${commit.author_name} · ${formatDate(commit.authored_at)}` })),
487
+ ],
488
+ })),
489
+ });
490
+ }
491
+ function GitReleaseList(props) {
492
+ const ui = useGitRepositoryUi();
493
+ const slot = useGitRepositorySlots();
494
+ const routes = useGitRepositoryRouteAdapter();
495
+ if (!props.releases.length) {
496
+ return h(GitEmptyState, { message: props.emptyMessage || "No releases have been published yet." });
497
+ }
498
+ return h("ul", {
499
+ ...slot("list", {}),
500
+ children: props.releases.map((release) => h("li", {
501
+ ...slot("list-item", {}),
502
+ key: release.id,
503
+ children: [
504
+ h("button", {
505
+ ...slot("list-link", {}),
506
+ key: "title",
507
+ onClick: () => ui.navigate(routes.release(props.repositoryKey, release.id)),
508
+ type: "button",
509
+ children: `${release.title} · ${release.tag_name}`,
510
+ }),
511
+ h("div", slot("note", { key: "meta", children: `${release.prerelease ? "Prerelease" : "Release"} · ${formatDate(release.published_at || release.created_at)}` })),
512
+ h("p", slot("note", { key: "notes", children: release.notes || "No release notes." })),
513
+ ],
514
+ })),
515
+ });
516
+ }
517
+ function GitForkList(props) {
518
+ const slot = useGitRepositorySlots();
519
+ if (!props.forks.length) {
520
+ return h(GitEmptyState, { message: "No forks exist for this repository yet." });
521
+ }
522
+ return h("ul", {
523
+ ...slot("list", {}),
524
+ children: props.forks.map((fork) => h("li", {
525
+ ...slot("list-item", {}),
526
+ key: fork.fork_repository_id,
527
+ children: [
528
+ h("strong", { key: "name", children: fork.fork_repository_id }),
529
+ h("div", slot("note", { key: "meta", children: `Ahead ${fork.fork_status.ahead} · Behind ${fork.fork_status.behind} · ${fork.fork_status.fork_branch}` })),
530
+ h(GitSyncForkButton, { forkId: fork.fork_repository_id, headers: props.headers, key: "sync", repositoryKey: props.repositoryKey }),
531
+ ],
532
+ })),
533
+ });
534
+ }
535
+ function GitTreeView(props) {
536
+ const slot = useGitRepositorySlots();
537
+ if (!props.entries.length) {
538
+ return h(GitEmptyState, { message: "This tree is empty." });
539
+ }
540
+ return h("ul", {
541
+ ...slot("list", {}),
542
+ children: props.entries.map((entry) => h("li", {
543
+ ...slot("list-item", {
544
+ className: entry.path === props.selectedPath ? "is-selected" : undefined,
545
+ }),
546
+ key: entry.path,
547
+ children: h("button", {
548
+ ...slot("list-link", {}),
549
+ onClick: () => props.onSelectPath?.(entry.path),
550
+ type: "button",
551
+ children: `${entry.type === "tree" ? "dir" : "file"} · ${entry.path}${entry.language ? ` · ${entry.language}` : ""}`,
552
+ }),
553
+ })),
554
+ });
555
+ }
556
+ function GitBlobView(props) {
557
+ const slot = useGitRepositorySlots();
558
+ return h("section", slot("card", {
559
+ children: [
560
+ h("div", slot("card-header", {
561
+ key: "header",
562
+ children: [
563
+ h("h2", slot("card-title", { key: "title", children: props.path || "File Preview" })),
564
+ props.subtitle ? h("div", slot("card-subtitle", { key: "subtitle", children: props.subtitle })) : null,
565
+ ],
566
+ })),
567
+ props.content
568
+ ? h("pre", slot("code-block", { key: "body", children: props.content }))
569
+ : h(GitEmptyState, { key: "empty", message: "Select a file to preview its content." }),
570
+ ],
571
+ }));
572
+ }
573
+ function GitSearchResults(props) {
574
+ const ui = useGitRepositoryUi();
575
+ const slot = useGitRepositorySlots();
576
+ const routes = useGitRepositoryRouteAdapter();
577
+ const files = props.results?.files || [];
578
+ if (!files.length) {
579
+ return h(GitEmptyState, { message: "No search results matched that query." });
580
+ }
581
+ return h("ul", {
582
+ ...slot("list", {}),
583
+ children: files.map((file) => h("li", {
584
+ ...slot("list-item", {}),
585
+ key: file.path,
586
+ children: [
587
+ h("button", {
588
+ ...slot("list-link", {}),
589
+ key: "path",
590
+ onClick: () => ui.navigate(routes.code(props.repositoryKey, file.path, props.results?.ref)),
591
+ type: "button",
592
+ children: `${file.path} · ${file.match_count} matches`,
593
+ }),
594
+ ...file.matches.slice(0, 5).map((match, index) => h("div", slot("note", {
595
+ key: `${file.path}:${index}`,
596
+ children: `${match.line_number}: ${match.line}`,
597
+ }))),
598
+ ],
599
+ })),
600
+ });
601
+ }
602
+ function GitActivityList(props) {
603
+ const slot = useGitRepositorySlots();
604
+ if (!props.activity.length) {
605
+ return h(GitEmptyState, { message: "There is no recorded activity yet." });
606
+ }
607
+ return h("ul", {
608
+ ...slot("list", {}),
609
+ children: props.activity.map((entry) => h("li", {
610
+ ...slot("list-item", {}),
611
+ key: entry.id,
612
+ children: [
613
+ h("strong", { key: "summary", children: entry.summary }),
614
+ h("div", slot("note", { key: "meta", children: `${entry.kind} · actor ${entry.actor_id} · ${formatDate(entry.created_at)}` })),
615
+ ],
616
+ })),
617
+ });
618
+ }
619
+ function GitBranchList(props) {
620
+ const ui = useGitRepositoryUi();
621
+ const slot = useGitRepositorySlots();
622
+ const routes = useGitRepositoryRouteAdapter();
623
+ if (!props.branches.length) {
624
+ return h(GitEmptyState, { message: "No branches are available." });
625
+ }
626
+ return h("ul", {
627
+ ...slot("list", {}),
628
+ children: props.branches.map((branch) => h("li", {
629
+ ...slot("list-item", {}),
630
+ key: branch.name,
631
+ children: [
632
+ h("button", {
633
+ ...slot("list-link", {}),
634
+ key: "branch",
635
+ onClick: () => ui.navigate(routes.code(props.repositoryKey, "", branch.name)),
636
+ type: "button",
637
+ children: branch.current ? `${branch.name} (current)` : branch.name,
638
+ }),
639
+ h("div", slot("note", { key: "meta", children: `${branch.head_commit.slice(0, 7)}${branch.upstream ? ` · ${branch.upstream}` : ""}` })),
640
+ ],
641
+ })),
642
+ });
643
+ }
644
+ function GitTagList(props) {
645
+ const ui = useGitRepositoryUi();
646
+ const slot = useGitRepositorySlots();
647
+ const routes = useGitRepositoryRouteAdapter();
648
+ if (!props.tags.length) {
649
+ return h(GitEmptyState, { message: "No tags exist yet." });
650
+ }
651
+ return h("ul", {
652
+ ...slot("list", {}),
653
+ children: props.tags.map((tag) => h("li", {
654
+ ...slot("list-item", {}),
655
+ key: tag.name,
656
+ children: [
657
+ h("button", {
658
+ ...slot("list-link", {}),
659
+ key: "tag",
660
+ onClick: () => ui.navigate(routes.code(props.repositoryKey, "", tag.name)),
661
+ type: "button",
662
+ children: tag.name,
663
+ }),
664
+ h("div", slot("note", { key: "meta", children: `${tag.short_hash} · ${tag.subject || "No subject"}` })),
665
+ ],
666
+ })),
667
+ });
668
+ }
669
+ function GitBlameView(props) {
670
+ const routes = useGitRepositoryRouteAdapter();
671
+ const ui = useGitRepositoryUi();
672
+ const slot = useGitRepositorySlots();
673
+ if (!props.blame || !props.blame.lines.length) {
674
+ return h(GitEmptyState, { message: "No blame lines were available for this file." });
675
+ }
676
+ return h("div", {
677
+ ...slot("blame", {}),
678
+ children: props.blame.lines.map((line) => h("div", {
679
+ ...slot("blame-row", {}),
680
+ key: `${line.line_number}:${line.commit_hash}`,
681
+ children: [
682
+ h("button", {
683
+ ...slot("blame-commit", {}),
684
+ key: "commit",
685
+ onClick: () => ui.navigate(routes.commit(props.repositoryKey, line.commit_hash)),
686
+ type: "button",
687
+ children: line.commit_short_hash,
688
+ }),
689
+ h("div", slot("note", { key: "meta", children: `${line.author_name} · ${formatDate(line.authored_at)}` })),
690
+ h("pre", slot("code-inline", { key: "content", children: line.content })),
691
+ ],
692
+ })),
693
+ });
694
+ }
695
+ function GitDiffView(props) {
696
+ const slot = useGitRepositorySlots();
697
+ if (!props.diff) {
698
+ return h(GitEmptyState, { message: "No comparison data is available." });
699
+ }
700
+ return h("div", slot("grid", {
701
+ children: [
702
+ h("section", slot("card", {
703
+ key: "summary",
704
+ children: [
705
+ h("div", slot("card-header", { key: "header", children: h("h2", slot("card-title", { children: "Compare Summary" })) })),
706
+ h("dl", slot("definition-grid", {
707
+ key: "body",
708
+ children: [
709
+ h("dt", { key: "base:label", children: "Base" }),
710
+ h("dd", { key: "base:value", children: props.diff.base_ref }),
711
+ h("dt", { key: "head:label", children: "Head" }),
712
+ h("dd", { key: "head:value", children: props.diff.head_ref }),
713
+ h("dt", { key: "commits:label", children: "Commits" }),
714
+ h("dd", { key: "commits:value", children: String(props.diff.commit_count) }),
715
+ h("dt", { key: "files:label", children: "Files" }),
716
+ h("dd", { key: "files:value", children: String(props.diff.file_count) }),
717
+ ],
718
+ })),
719
+ ],
720
+ })),
721
+ h("section", slot("card", {
722
+ className: "git-browser-span-2",
723
+ key: "diff",
724
+ children: [
725
+ h("div", slot("card-header", { key: "header", children: h("h2", slot("card-title", { children: "Diff" })) })),
726
+ h("pre", slot("code-block", { key: "body", children: props.diff.diff })),
727
+ ],
728
+ })),
729
+ ],
730
+ }));
731
+ }
732
+ export { GitActivityList, GitBlameView, GitBlobView, GitBranchList, GitBranchSelector, GitCommitList, GitCopyCloneUrlButton, GitCreateReleaseButton, GitDeleteReleaseButton, GitDiffView, GitDownloadArchiveButton, GitEditReleaseButton, GitEmptyState, GitErrorState, GitForkButton, GitForkList, GitLoadingState, GitPathBreadcrumbs, GitReleaseList, GitRepositoryActionBar, GitRepositoryHeader, GitRepositoryShell, GitRepositorySocialButtons, GitRepositoryStats, GitRepositoryTabs, GitRepositoryUiProvider, GitSearchResults, GitStarButton, GitSyncForkButton, GitTagList, GitTagSelector, GitTreeView, GitWatchButton, };
733
+ //# sourceMappingURL=components.js.map