@grimoire-rs/indexer 0.5.0 → 0.5.2
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/CHANGELOG.md +117 -1
- package/dist/cli/dev.d.ts +14 -0
- package/dist/cli/dev.d.ts.map +1 -1
- package/dist/cli/dev.js +22 -1
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +5 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/renderer/astro/components/Catalog.js +146 -24
- package/dist/renderer/astro/components/Catalog.tsx +200 -31
- package/dist/renderer/astro/components/CodeBlock.astro +74 -0
- package/dist/renderer/astro/components/PackageCard.js +1 -1
- package/dist/renderer/astro/components/PackageCard.tsx +9 -1
- package/dist/renderer/astro/layouts/Base.astro +196 -83
- package/dist/renderer/astro/lib/code.d.ts +2 -2
- package/dist/renderer/astro/lib/code.js +2 -2
- package/dist/renderer/astro/lib/code.ts +2 -2
- package/dist/renderer/astro/lib/commands.d.ts +9 -3
- package/dist/renderer/astro/lib/commands.js +10 -5
- package/dist/renderer/astro/lib/commands.ts +22 -6
- package/dist/renderer/astro/pages/p/[...slug].astro +23 -17
- package/dist/renderer/index.d.ts +19 -0
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +18 -2
- package/dist/renderer/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -279,10 +279,25 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
279
279
|
'<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>';
|
|
280
280
|
|
|
281
281
|
for (const pre of document.querySelectorAll("pre.astro-code")) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
282
|
+
// `CodeBlock.astro` already ships the wrapper and the action slot, so
|
|
283
|
+
// adopt them where they are there. Wrapping a second time would nest
|
|
284
|
+
// two positioning contexts and orphan whatever the component put in
|
|
285
|
+
// the slot.
|
|
286
|
+
const parent = pre.parentElement;
|
|
287
|
+
let wrapper = parent?.classList.contains("code-block") ? parent : null;
|
|
288
|
+
if (!wrapper) {
|
|
289
|
+
wrapper = document.createElement("div");
|
|
290
|
+
wrapper.className = "code-block";
|
|
291
|
+
pre.replaceWith(wrapper);
|
|
292
|
+
wrapper.append(pre);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let actions = wrapper.querySelector(".code-actions");
|
|
296
|
+
if (!actions) {
|
|
297
|
+
actions = document.createElement("span");
|
|
298
|
+
actions.className = "code-actions";
|
|
299
|
+
wrapper.append(actions);
|
|
300
|
+
}
|
|
286
301
|
|
|
287
302
|
const btn = document.createElement("button");
|
|
288
303
|
btn.type = "button";
|
|
@@ -292,9 +307,10 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
292
307
|
// `textContent`, not `innerText`: the block is not rendered yet at
|
|
293
308
|
// this point, and `innerText` would collapse its whitespace.
|
|
294
309
|
btn.dataset.copy = pre.textContent ?? "";
|
|
295
|
-
|
|
310
|
+
// A component-rendered block names itself; a markdown one cannot.
|
|
311
|
+
btn.dataset.copyName = wrapper.dataset.copyName || "code block";
|
|
296
312
|
btn.innerHTML = CLIPBOARD_ICON + '<span class="sr-only" role="status"></span>';
|
|
297
|
-
|
|
313
|
+
actions.append(btn);
|
|
298
314
|
}
|
|
299
315
|
|
|
300
316
|
for (const btn of document.querySelectorAll("[data-copy]")) {
|
|
@@ -833,10 +849,6 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
833
849
|
font-size: var(--grim-text-md);
|
|
834
850
|
min-width: 0;
|
|
835
851
|
}
|
|
836
|
-
.controls input[type="search"]:focus-visible {
|
|
837
|
-
outline: 2px solid var(--grim-color-accent);
|
|
838
|
-
outline-offset: 1px;
|
|
839
|
-
}
|
|
840
852
|
/* The `/` shortcut, shown as the key it is. It is a hint for a field
|
|
841
853
|
that is not yet in use, so it withdraws the moment the field is
|
|
842
854
|
focused or holds a query — at which point it would only be
|
|
@@ -917,6 +929,20 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
917
929
|
.chip.deprecated-toggle {
|
|
918
930
|
flex-shrink: 0;
|
|
919
931
|
}
|
|
932
|
+
/* Lifts every keyword at once, and is only in the markup while there
|
|
933
|
+
is one to lift — so it never competes with the rail for room in the
|
|
934
|
+
common case. Muted until hovered: it undoes work, and it should not
|
|
935
|
+
read as another facet to pick. */
|
|
936
|
+
.chip.kw-clear {
|
|
937
|
+
flex-shrink: 0;
|
|
938
|
+
gap: var(--grim-space-2);
|
|
939
|
+
color: var(--grim-color-muted);
|
|
940
|
+
}
|
|
941
|
+
.chip.kw-clear:hover,
|
|
942
|
+
.chip.kw-clear:focus-visible {
|
|
943
|
+
border-color: var(--grim-color-accent);
|
|
944
|
+
color: var(--grim-color-fg);
|
|
945
|
+
}
|
|
920
946
|
.kw-menu {
|
|
921
947
|
flex-shrink: 0;
|
|
922
948
|
}
|
|
@@ -996,11 +1022,6 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
996
1022
|
.sort-field:focus-visible {
|
|
997
1023
|
z-index: 1;
|
|
998
1024
|
}
|
|
999
|
-
.sort-dir:focus-visible,
|
|
1000
|
-
.sort-field:focus-visible {
|
|
1001
|
-
outline: 2px solid var(--grim-color-accent);
|
|
1002
|
-
outline-offset: 1px;
|
|
1003
|
-
}
|
|
1004
1025
|
/* One box for every chip in the filter row — the kinds, the keywords,
|
|
1005
1026
|
the deprecated toggle and the overflow menu's trigger alike. The
|
|
1006
1027
|
line-height is stated rather than inherited because a `<summary>`
|
|
@@ -1032,66 +1053,68 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1032
1053
|
background: var(--grim-color-accent-soft);
|
|
1033
1054
|
}
|
|
1034
1055
|
/* The keyword rail reorders on every click — it is rescored against
|
|
1035
|
-
what is on screen — and the chips slide rather than jump.
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
/* The overflow menu. A `<details>` for the same reasons the platform
|
|
1051
|
-
picker is one — it opens, closes and takes Escape without a line of
|
|
1052
|
-
script — and the panel is the `.os-menu` popover's measurements so
|
|
1053
|
-
the two read as the same object in two places. */
|
|
1056
|
+
what is on screen — and the chips slide rather than jump. There is
|
|
1057
|
+
deliberately no `translate` transition here: the FLIP effect in
|
|
1058
|
+
`Catalog.tsx` runs each slide as a Web Animation instead, reading
|
|
1059
|
+
`--grim-duration-slow` for its length and honouring
|
|
1060
|
+
`prefers-reduced-motion` itself. A transition needs an inline style
|
|
1061
|
+
to drive it, and an inline style is what a superseded pass used to
|
|
1062
|
+
leave behind on a chip stopped off its seat. */
|
|
1063
|
+
/* The overflow menu. A popover, and it has to be one: `.filter-row`
|
|
1064
|
+
above is a scroll container, and an absolutely-positioned panel
|
|
1065
|
+
inside a scroll container is cropped to the row AND stretches the
|
|
1066
|
+
row's scroll extent — which is where a menu that opened invisibly,
|
|
1067
|
+
with a stray horizontal and vertical scrollbar to show for it, came
|
|
1068
|
+
from. The top layer is outside every ancestor's `overflow`, and it
|
|
1069
|
+
brings light dismiss and Escape, which the `<details>` this replaced
|
|
1070
|
+
never had. Its seat is `placeKwMenu` in `Catalog.tsx`. */
|
|
1054
1071
|
.kw-menu {
|
|
1055
|
-
position: relative;
|
|
1056
1072
|
display: flex;
|
|
1057
1073
|
}
|
|
1058
1074
|
/* The trigger wears `.chip`, so its box comes from there and cannot
|
|
1059
1075
|
drift a pixel off the chips it sits beside. Only what a chip does
|
|
1060
1076
|
not cover is stated here. */
|
|
1061
|
-
.kw-menu >
|
|
1077
|
+
.kw-menu > button {
|
|
1062
1078
|
display: inline-flex;
|
|
1063
1079
|
align-items: center;
|
|
1064
1080
|
color: var(--grim-color-muted);
|
|
1065
|
-
/* Both spellings: the default triangle is a marker in Firefox and
|
|
1066
|
-
a `::-webkit-details-marker` pseudo-element in older WebKit. */
|
|
1067
|
-
list-style: none;
|
|
1068
1081
|
}
|
|
1069
|
-
.kw-menu >
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
.kw-menu > summary:hover,
|
|
1073
|
-
.kw-menu > summary:focus-visible,
|
|
1074
|
-
.kw-menu[open] > summary {
|
|
1082
|
+
.kw-menu > button:hover,
|
|
1083
|
+
.kw-menu > button:focus-visible,
|
|
1084
|
+
.kw-menu > button[aria-expanded="true"] {
|
|
1075
1085
|
border-color: var(--grim-color-accent);
|
|
1076
1086
|
color: var(--grim-color-fg);
|
|
1077
1087
|
}
|
|
1088
|
+
/* `inset` and `margin` undo the UA's centring of a popover, so the
|
|
1089
|
+
`left`/`top` the script writes are the whole position. `color` is
|
|
1090
|
+
restated because the UA sets `CanvasText` on `[popover]` directly,
|
|
1091
|
+
which beats what the panel would otherwise inherit. `display` is
|
|
1092
|
+
deliberately absent: the UA's `display: none` for a closed popover
|
|
1093
|
+
has to keep winning, so the flex box is declared on `:popover-open`
|
|
1094
|
+
alone — an unconditional `display` here would show the menu shut. */
|
|
1078
1095
|
.kw-menu-panel {
|
|
1079
|
-
position:
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
z-index: 5;
|
|
1083
|
-
display: flex;
|
|
1084
|
-
flex-direction: column;
|
|
1085
|
-
gap: var(--grim-space-3);
|
|
1096
|
+
position: fixed;
|
|
1097
|
+
inset: auto;
|
|
1098
|
+
margin: 0;
|
|
1086
1099
|
/* The panel's own measurement: wide enough for the longest keyword
|
|
1087
1100
|
a publisher is likely to write plus its count, and capped so a
|
|
1088
1101
|
long vocabulary scrolls instead of running off the viewport. */
|
|
1089
1102
|
width: 15rem;
|
|
1090
1103
|
padding: var(--grim-space-3);
|
|
1091
1104
|
background: var(--grim-color-card);
|
|
1105
|
+
color: var(--grim-color-fg);
|
|
1092
1106
|
border: var(--grim-border-width) solid var(--grim-color-border);
|
|
1093
1107
|
border-radius: var(--grim-radius-control);
|
|
1094
1108
|
box-shadow: var(--grim-shadow-raised);
|
|
1109
|
+
/* The list inside is the thing that scrolls. Without this the UA's
|
|
1110
|
+
own `overflow: auto` on `[popover]` adds a second scrollbar once
|
|
1111
|
+
the script caps the panel's height. */
|
|
1112
|
+
overflow: hidden;
|
|
1113
|
+
}
|
|
1114
|
+
.kw-menu-panel:popover-open {
|
|
1115
|
+
display: flex;
|
|
1116
|
+
flex-direction: column;
|
|
1117
|
+
gap: var(--grim-space-3);
|
|
1095
1118
|
}
|
|
1096
1119
|
.kw-menu-search {
|
|
1097
1120
|
width: 100%;
|
|
@@ -1103,10 +1126,6 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1103
1126
|
font: inherit;
|
|
1104
1127
|
font-size: var(--grim-text-sm);
|
|
1105
1128
|
}
|
|
1106
|
-
.kw-menu-search:focus-visible {
|
|
1107
|
-
outline: 2px solid var(--grim-color-accent);
|
|
1108
|
-
outline-offset: 1px;
|
|
1109
|
-
}
|
|
1110
1129
|
.kw-menu-list {
|
|
1111
1130
|
display: flex;
|
|
1112
1131
|
flex-direction: column;
|
|
@@ -1115,6 +1134,11 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1115
1134
|
as a list rather than a page. */
|
|
1116
1135
|
max-height: 15rem;
|
|
1117
1136
|
overflow-y: auto;
|
|
1137
|
+
/* And shorter still where the panel's own cap is tighter — a
|
|
1138
|
+
flex item's automatic minimum size is its content, so without
|
|
1139
|
+
`min-height` the list refuses to shrink and overflows the panel
|
|
1140
|
+
the script just sized to the space below the trigger. */
|
|
1141
|
+
min-height: 0;
|
|
1118
1142
|
}
|
|
1119
1143
|
.kw-menu-item {
|
|
1120
1144
|
display: flex;
|
|
@@ -1195,9 +1219,26 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1195
1219
|
.view-pick.active {
|
|
1196
1220
|
z-index: 1;
|
|
1197
1221
|
}
|
|
1222
|
+
|
|
1223
|
+
/* One focus ring for every bordered control in the toolbar, and it is
|
|
1224
|
+
the card's: the border takes the accent and the outline sits
|
|
1225
|
+
directly on it, so the two merge into one thicker edge.
|
|
1226
|
+
|
|
1227
|
+
An offset ring is what put two borders on the sort combo. Hover
|
|
1228
|
+
already tints the border, so a ring standing 1px clear of it drew a
|
|
1229
|
+
second line in the same colour — one state reading as two. Every
|
|
1230
|
+
control here tints its border on hover or while active, so the
|
|
1231
|
+
offset had to go from all of them together rather than from the one
|
|
1232
|
+
that was reported. */
|
|
1233
|
+
.chip:focus-visible,
|
|
1234
|
+
.controls input[type="search"]:focus-visible,
|
|
1235
|
+
.kw-menu-search:focus-visible,
|
|
1236
|
+
.sort-dir:focus-visible,
|
|
1237
|
+
.sort-field:focus-visible,
|
|
1198
1238
|
.view-pick:focus-visible {
|
|
1199
1239
|
outline: 2px solid var(--grim-color-accent);
|
|
1200
|
-
outline-offset:
|
|
1240
|
+
outline-offset: 0;
|
|
1241
|
+
border-color: var(--grim-color-accent);
|
|
1201
1242
|
}
|
|
1202
1243
|
|
|
1203
1244
|
.grid {
|
|
@@ -1208,6 +1249,27 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1208
1249
|
grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
|
|
1209
1250
|
gap: var(--grim-space-6);
|
|
1210
1251
|
}
|
|
1252
|
+
/* Off-screen cards skip layout and paint until they are scrolled to.
|
|
1253
|
+
A card is the expensive item on this page — a masked keyword strip,
|
|
1254
|
+
a clipped watermark in its own stacking context, a logo — and the
|
|
1255
|
+
grid and the table are separate component trees, so switching view
|
|
1256
|
+
repaints every one of them at once.
|
|
1257
|
+
|
|
1258
|
+
`auto` remembers each card's last real height, so the scrollbar
|
|
1259
|
+
stops jumping after the first pass; the `18rem` is only the guess
|
|
1260
|
+
before that. Cards stay focusable and findable — the engine renders
|
|
1261
|
+
one on focus or find-in-page.
|
|
1262
|
+
|
|
1263
|
+
ponytail: this bounds the PAINT, not the JS. Measured in jsdom (no
|
|
1264
|
+
layout at all) the Preact commit for one view switch is ~30ms at 100
|
|
1265
|
+
packages, ~90-170ms at 500 and ~180-350ms at 1000, because the two
|
|
1266
|
+
views share no element types and every card unmounts as every row
|
|
1267
|
+
mounts. Past a few hundred packages the answer is windowing the
|
|
1268
|
+
list, not another CSS property. */
|
|
1269
|
+
.grid > li {
|
|
1270
|
+
content-visibility: auto;
|
|
1271
|
+
contain-intrinsic-size: auto 18rem;
|
|
1272
|
+
}
|
|
1211
1273
|
.card {
|
|
1212
1274
|
display: flex;
|
|
1213
1275
|
flex-direction: column;
|
|
@@ -1351,10 +1413,6 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1351
1413
|
height: 36px;
|
|
1352
1414
|
border-radius: var(--grim-radius-inset);
|
|
1353
1415
|
}
|
|
1354
|
-
img.card-logo {
|
|
1355
|
-
object-fit: contain;
|
|
1356
|
-
background: var(--grim-color-chip-bg);
|
|
1357
|
-
}
|
|
1358
1416
|
.card-logo-fallback {
|
|
1359
1417
|
display: flex;
|
|
1360
1418
|
align-items: center;
|
|
@@ -1375,17 +1433,26 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1375
1433
|
|
|
1376
1434
|
loading placeholder, no slash — the resting state
|
|
1377
1435
|
ready image faded in, placeholder faded out
|
|
1378
|
-
broken placeholder with its slash
|
|
1436
|
+
broken placeholder with its slash
|
|
1379
1437
|
|
|
1380
1438
|
Kept distinct from `.card-logo-fallback`: that is a package with
|
|
1381
1439
|
no logo at all, which is normal, not a fault. */
|
|
1440
|
+
/* No background. A logo is already a designed mark on its own ground,
|
|
1441
|
+
and a tinted square behind it framed it twice — worst on the many
|
|
1442
|
+
logos that are themselves a rounded square, which then sat inside a
|
|
1443
|
+
slightly larger rounded square. What is left is a box with a size,
|
|
1444
|
+
so the three states still swap without shifting anything. Nothing is
|
|
1445
|
+
drawn in any of them: the placeholder and the broken glyph carry
|
|
1446
|
+
their own colour, and the slash is what separates the two — a
|
|
1447
|
+
dashed frame around the broken one read as a fault in the layout
|
|
1448
|
+
rather than in the image, which is not what it means. The state is
|
|
1449
|
+
still announced, through `role="img"` and a label on the slot. */
|
|
1382
1450
|
.logo-slot {
|
|
1383
1451
|
position: relative;
|
|
1384
1452
|
display: flex;
|
|
1385
1453
|
align-items: center;
|
|
1386
1454
|
justify-content: center;
|
|
1387
1455
|
overflow: hidden;
|
|
1388
|
-
background: var(--grim-color-chip-bg);
|
|
1389
1456
|
color: var(--grim-color-muted);
|
|
1390
1457
|
}
|
|
1391
1458
|
.logo-slot .logo-mark,
|
|
@@ -1418,9 +1485,6 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1418
1485
|
.logo-slot:not([data-state="broken"]) .mark-broken {
|
|
1419
1486
|
display: none;
|
|
1420
1487
|
}
|
|
1421
|
-
.logo-slot[data-state="broken"] {
|
|
1422
|
-
border: var(--grim-border-width) dashed var(--grim-color-border);
|
|
1423
|
-
}
|
|
1424
1488
|
@media (prefers-reduced-motion: reduce) {
|
|
1425
1489
|
.logo-slot .logo-mark,
|
|
1426
1490
|
.logo-slot img {
|
|
@@ -1524,10 +1588,7 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1524
1588
|
name beside it starts on one line down the whole list. The colour
|
|
1525
1589
|
is set inline, from the kind's own token or the deprecation one. */
|
|
1526
1590
|
.t-kind {
|
|
1527
|
-
|
|
1528
|
-
}
|
|
1529
|
-
.t-kind svg {
|
|
1530
|
-
vertical-align: middle;
|
|
1591
|
+
justify-content: center;
|
|
1531
1592
|
}
|
|
1532
1593
|
/* The card's tile at a row's height. Geometry, not a scale step, and
|
|
1533
1594
|
measured against the text line beside it rather than against the
|
|
@@ -1561,23 +1622,33 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1561
1622
|
wide cell — they are one reading, and the gap that separated them
|
|
1562
1623
|
was the cell's width showing through. */
|
|
1563
1624
|
.t-rating {
|
|
1564
|
-
|
|
1625
|
+
justify-content: flex-end;
|
|
1565
1626
|
color: var(--grim-color-muted);
|
|
1566
1627
|
}
|
|
1567
1628
|
.t-rating svg {
|
|
1568
|
-
vertical-align: middle;
|
|
1569
1629
|
margin-left: var(--grim-space-2);
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1630
|
+
}
|
|
1631
|
+
/* The two cells that carry a glyph centre it as a box, not on the
|
|
1632
|
+
text line. `vertical-align: middle` aligns to half the x-height,
|
|
1633
|
+
which sits about 2px under the line's true middle at this step —
|
|
1634
|
+
the eye reads that as the mark and the arrow sagging below the
|
|
1635
|
+
words beside them. Neither cell owes anything to the row's
|
|
1636
|
+
no-flex rule above: the kind is one mark and the rating is a
|
|
1637
|
+
fixed-width count plus its arrow, so there is no text here for
|
|
1638
|
+
`text-overflow` to elide. */
|
|
1639
|
+
.t-kind,
|
|
1640
|
+
.t-rating {
|
|
1641
|
+
display: flex;
|
|
1642
|
+
align-items: center;
|
|
1574
1643
|
}
|
|
1575
1644
|
/* The count carries the column's alignment, and the arrow after it
|
|
1576
1645
|
inherits it: a fixed box, right-aligned, in tabular figures. Without
|
|
1577
1646
|
the fixed box a three-digit count would push its own arrow right of
|
|
1578
1647
|
the one above it. Geometry — it holds four digits at this step. */
|
|
1579
1648
|
.t-votes {
|
|
1580
|
-
|
|
1649
|
+
/* Never shrunk to its digits: the box is what holds the arrow
|
|
1650
|
+
after it in one place down the column. */
|
|
1651
|
+
flex: none;
|
|
1581
1652
|
width: 2rem;
|
|
1582
1653
|
text-align: right;
|
|
1583
1654
|
font-variant-numeric: tabular-nums;
|
|
@@ -1670,6 +1741,34 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1670
1741
|
font-size: var(--grim-text-xs);
|
|
1671
1742
|
line-height: 1.3;
|
|
1672
1743
|
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
1744
|
+
/* One line, whatever the address is. A namespace breaks at its own
|
|
1745
|
+
slashes and dots, so left to itself a long one wrapped to a second
|
|
1746
|
+
line and made the card's head taller than its neighbours'. */
|
|
1747
|
+
display: flex;
|
|
1748
|
+
min-width: 0;
|
|
1749
|
+
white-space: nowrap;
|
|
1750
|
+
}
|
|
1751
|
+
/* Trimmed from the FRONT: `github.com/` is on every address in an
|
|
1752
|
+
index and the repository at the tail is what tells two apart, so the
|
|
1753
|
+
head is what to spend.
|
|
1754
|
+
|
|
1755
|
+
`direction: rtl` is the mechanism — `text-overflow` ellipsises at
|
|
1756
|
+
the line's inline END, which in an RTL box is its left edge, and
|
|
1757
|
+
`text-align: left` keeps a short address sitting under the name
|
|
1758
|
+
rather than flung to the right. The address itself still reads
|
|
1759
|
+
left-to-right: it is one run of Latin characters, so the bidi
|
|
1760
|
+
algorithm lays it out LTR inside the RTL box. That holds because a
|
|
1761
|
+
namespace neither starts nor ends with punctuation — one that did
|
|
1762
|
+
would have that character reordered to the far end.
|
|
1763
|
+
|
|
1764
|
+
The two-value `text-overflow: ellipsis ""` would say this directly
|
|
1765
|
+
and is Firefox-only. */
|
|
1766
|
+
.namespace .address {
|
|
1767
|
+
min-width: 0;
|
|
1768
|
+
overflow: hidden;
|
|
1769
|
+
text-overflow: ellipsis;
|
|
1770
|
+
direction: rtl;
|
|
1771
|
+
text-align: left;
|
|
1673
1772
|
}
|
|
1674
1773
|
/* The rating is one control with two halves — the count, which opens
|
|
1675
1774
|
the forge thread, and the vote, which casts one — joined the way
|
|
@@ -1912,12 +2011,21 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1912
2011
|
.astro-code span:not([style*="background"]) {
|
|
1913
2012
|
background-color: transparent !important;
|
|
1914
2013
|
}
|
|
1915
|
-
/*
|
|
1916
|
-
|
|
1917
|
-
|
|
2014
|
+
/* The corner the block's buttons sit in. It is a row rather than one
|
|
2015
|
+
positioned button because `CodeBlock.astro` can add a second one —
|
|
2016
|
+
a VS Code deep link — and the copy button `Base.astro` injects has
|
|
2017
|
+
to land beside it without either knowing the other's width. */
|
|
2018
|
+
.code-actions {
|
|
1918
2019
|
position: absolute;
|
|
1919
2020
|
top: 0.45rem;
|
|
1920
2021
|
right: 0.45rem;
|
|
2022
|
+
display: flex;
|
|
2023
|
+
gap: var(--grim-space-2);
|
|
2024
|
+
}
|
|
2025
|
+
/* Reveals on hover or keyboard focus, so they are not a permanent
|
|
2026
|
+
smudge over the first line of every block. */
|
|
2027
|
+
.code-copy,
|
|
2028
|
+
.code-vscode {
|
|
1921
2029
|
display: inline-flex;
|
|
1922
2030
|
align-items: center;
|
|
1923
2031
|
justify-content: center;
|
|
@@ -1928,6 +2036,7 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1928
2036
|
border-radius: var(--grim-radius-inset);
|
|
1929
2037
|
background: var(--grim-color-card);
|
|
1930
2038
|
color: var(--grim-color-muted);
|
|
2039
|
+
text-decoration: none;
|
|
1931
2040
|
cursor: pointer;
|
|
1932
2041
|
opacity: 0;
|
|
1933
2042
|
transition:
|
|
@@ -1936,10 +2045,13 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1936
2045
|
border-color var(--grim-duration-fast) ease;
|
|
1937
2046
|
}
|
|
1938
2047
|
.code-block:hover .code-copy,
|
|
1939
|
-
.code-
|
|
2048
|
+
.code-block:hover .code-vscode,
|
|
2049
|
+
.code-copy:focus-visible,
|
|
2050
|
+
.code-vscode:focus-visible {
|
|
1940
2051
|
opacity: 1;
|
|
1941
2052
|
}
|
|
1942
|
-
.code-copy:hover
|
|
2053
|
+
.code-copy:hover,
|
|
2054
|
+
.code-vscode:hover {
|
|
1943
2055
|
color: var(--grim-color-accent);
|
|
1944
2056
|
border-color: var(--grim-color-accent);
|
|
1945
2057
|
}
|
|
@@ -1949,7 +2061,8 @@ const { title, description, image = config.logo ?? config.favicon } = Astro.prop
|
|
|
1949
2061
|
opacity: 1;
|
|
1950
2062
|
}
|
|
1951
2063
|
@media (prefers-reduced-motion: reduce) {
|
|
1952
|
-
.code-copy
|
|
2064
|
+
.code-copy,
|
|
2065
|
+
.code-vscode {
|
|
1953
2066
|
transition: none;
|
|
1954
2067
|
}
|
|
1955
2068
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Shiki is what Astro already ships — the same highlighter VS Code renders
|
|
5
5
|
* with — so nothing here adds a library; this only stops the two consumers
|
|
6
6
|
* drifting onto different themes. The markdown pipeline reads it through
|
|
7
|
-
* `astro.config`'s `shikiConfig`, and
|
|
8
|
-
*
|
|
7
|
+
* `astro.config`'s `shikiConfig`, and `CodeBlock.astro` — what every
|
|
8
|
+
* hand-written snippet on the site goes through — passes it to `<Code>`.
|
|
9
9
|
*
|
|
10
10
|
* A *pair*, not one theme: with a single theme a block stays dark on a light
|
|
11
11
|
* page. Given two, Shiki writes the light colour as an inline style and the
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* Shiki is what Astro already ships — the same highlighter VS Code renders
|
|
7
7
|
* with — so nothing here adds a library; this only stops the two consumers
|
|
8
8
|
* drifting onto different themes. The markdown pipeline reads it through
|
|
9
|
-
* `astro.config`'s `shikiConfig`, and
|
|
10
|
-
*
|
|
9
|
+
* `astro.config`'s `shikiConfig`, and `CodeBlock.astro` — what every
|
|
10
|
+
* hand-written snippet on the site goes through — passes it to `<Code>`.
|
|
11
11
|
*
|
|
12
12
|
* A *pair*, not one theme: with a single theme a block stays dark on a light
|
|
13
13
|
* page. Given two, Shiki writes the light colour as an inline style and the
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* Shiki is what Astro already ships — the same highlighter VS Code renders
|
|
8
8
|
* with — so nothing here adds a library; this only stops the two consumers
|
|
9
9
|
* drifting onto different themes. The markdown pipeline reads it through
|
|
10
|
-
* `astro.config`'s `shikiConfig`, and
|
|
11
|
-
*
|
|
10
|
+
* `astro.config`'s `shikiConfig`, and `CodeBlock.astro` — what every
|
|
11
|
+
* hand-written snippet on the site goes through — passes it to `<Code>`.
|
|
12
12
|
*
|
|
13
13
|
* A *pair*, not one theme: with a single theme a block stays dark on a light
|
|
14
14
|
* page. Given two, Shiki writes the light colour as an inline style and the
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ResolvedSiteConfig } from "../../../config.js";
|
|
1
|
+
import type { RegistryHint, ResolvedSiteConfig } from "../../../config.js";
|
|
2
|
+
export type { RegistryHint };
|
|
2
3
|
/**
|
|
3
4
|
* One option in a command bar: what it is called, what it copies, and the
|
|
4
5
|
* glyph that stands for it.
|
|
@@ -35,8 +36,13 @@ export declare function installChoices(config: ResolvedSiteConfig): Choice[];
|
|
|
35
36
|
* the `helm repo add` ergonomic. `null` when `registry` is unconfigured,
|
|
36
37
|
* which means the index has no public URL to hand out; the block is omitted
|
|
37
38
|
* rather than guessed.
|
|
39
|
+
*
|
|
40
|
+
* `registry` defaults to the site's own, and is a parameter so a page can draw
|
|
41
|
+
* the same bar for a *different* index: a corporate setup guide that hands out
|
|
42
|
+
* its own index in the hero and the public one further down needs two bars
|
|
43
|
+
* differing in nothing but this argument.
|
|
38
44
|
*/
|
|
39
|
-
export declare function registryAddCommand(config: ResolvedSiteConfig): string | null;
|
|
45
|
+
export declare function registryAddCommand(config: ResolvedSiteConfig, registry?: RegistryHint | null): string | null;
|
|
40
46
|
/**
|
|
41
47
|
* Scope choices for the registry-add bar. Empty when there is no command to
|
|
42
48
|
* scope — the bar can still render for the sake of its VS Code segment.
|
|
@@ -49,7 +55,7 @@ export declare function registryAddCommand(config: ResolvedSiteConfig): string |
|
|
|
49
55
|
* flag, and appended after a long `--index <url>` it fell off the end of the
|
|
50
56
|
* line, so switching scope looked like it changed nothing at all.
|
|
51
57
|
*/
|
|
52
|
-
export declare function registryScopeChoices(config: ResolvedSiteConfig): Choice[];
|
|
58
|
+
export declare function registryScopeChoices(config: ResolvedSiteConfig, registry?: RegistryHint | null): Choice[];
|
|
53
59
|
/**
|
|
54
60
|
* Scope choices for adding one package — the same two-way choice, the same
|
|
55
61
|
* two glyphs, the same order as the registry bar and the package cards.
|
|
@@ -47,10 +47,15 @@ export function installChoices(config) {
|
|
|
47
47
|
* the `helm repo add` ergonomic. `null` when `registry` is unconfigured,
|
|
48
48
|
* which means the index has no public URL to hand out; the block is omitted
|
|
49
49
|
* rather than guessed.
|
|
50
|
+
*
|
|
51
|
+
* `registry` defaults to the site's own, and is a parameter so a page can draw
|
|
52
|
+
* the same bar for a *different* index: a corporate setup guide that hands out
|
|
53
|
+
* its own index in the hero and the public one further down needs two bars
|
|
54
|
+
* differing in nothing but this argument.
|
|
50
55
|
*/
|
|
51
|
-
export function registryAddCommand(config) {
|
|
52
|
-
return
|
|
53
|
-
? `grim config registry add ${
|
|
56
|
+
export function registryAddCommand(config, registry = config.registry) {
|
|
57
|
+
return registry
|
|
58
|
+
? `grim config registry add ${registry.alias} --index ${registry.index}`
|
|
54
59
|
: null;
|
|
55
60
|
}
|
|
56
61
|
/**
|
|
@@ -65,8 +70,8 @@ export function registryAddCommand(config) {
|
|
|
65
70
|
* flag, and appended after a long `--index <url>` it fell off the end of the
|
|
66
71
|
* line, so switching scope looked like it changed nothing at all.
|
|
67
72
|
*/
|
|
68
|
-
export function registryScopeChoices(config) {
|
|
69
|
-
const add = registryAddCommand(config);
|
|
73
|
+
export function registryScopeChoices(config, registry = config.registry) {
|
|
74
|
+
const add = registryAddCommand(config, registry);
|
|
70
75
|
if (!add)
|
|
71
76
|
return [];
|
|
72
77
|
return [
|
|
@@ -20,7 +20,12 @@ import {
|
|
|
20
20
|
mdiMicrosoftWindows,
|
|
21
21
|
mdiPenguin,
|
|
22
22
|
} from "@mdi/js";
|
|
23
|
-
import type { ResolvedSiteConfig } from "../../../config.js";
|
|
23
|
+
import type { RegistryHint, ResolvedSiteConfig } from "../../../config.js";
|
|
24
|
+
|
|
25
|
+
// Re-exported so an index's own page can name the shape it passes to the two
|
|
26
|
+
// functions below without reaching past `@grim/lib/*` into the package's
|
|
27
|
+
// internals, which the overlay does not publish.
|
|
28
|
+
export type { RegistryHint };
|
|
24
29
|
|
|
25
30
|
/**
|
|
26
31
|
* One option in a command bar: what it is called, what it copies, and the
|
|
@@ -77,10 +82,18 @@ export function installChoices(config: ResolvedSiteConfig): Choice[] {
|
|
|
77
82
|
* the `helm repo add` ergonomic. `null` when `registry` is unconfigured,
|
|
78
83
|
* which means the index has no public URL to hand out; the block is omitted
|
|
79
84
|
* rather than guessed.
|
|
85
|
+
*
|
|
86
|
+
* `registry` defaults to the site's own, and is a parameter so a page can draw
|
|
87
|
+
* the same bar for a *different* index: a corporate setup guide that hands out
|
|
88
|
+
* its own index in the hero and the public one further down needs two bars
|
|
89
|
+
* differing in nothing but this argument.
|
|
80
90
|
*/
|
|
81
|
-
export function registryAddCommand(
|
|
82
|
-
|
|
83
|
-
|
|
91
|
+
export function registryAddCommand(
|
|
92
|
+
config: ResolvedSiteConfig,
|
|
93
|
+
registry: RegistryHint | null = config.registry,
|
|
94
|
+
): string | null {
|
|
95
|
+
return registry
|
|
96
|
+
? `grim config registry add ${registry.alias} --index ${registry.index}`
|
|
84
97
|
: null;
|
|
85
98
|
}
|
|
86
99
|
|
|
@@ -96,8 +109,11 @@ export function registryAddCommand(config: ResolvedSiteConfig): string | null {
|
|
|
96
109
|
* flag, and appended after a long `--index <url>` it fell off the end of the
|
|
97
110
|
* line, so switching scope looked like it changed nothing at all.
|
|
98
111
|
*/
|
|
99
|
-
export function registryScopeChoices(
|
|
100
|
-
|
|
112
|
+
export function registryScopeChoices(
|
|
113
|
+
config: ResolvedSiteConfig,
|
|
114
|
+
registry: RegistryHint | null = config.registry,
|
|
115
|
+
): Choice[] {
|
|
116
|
+
const add = registryAddCommand(config, registry);
|
|
101
117
|
if (!add) return [];
|
|
102
118
|
return [
|
|
103
119
|
{ name: "Global", command: `grim --global ${add.slice("grim ".length)}`, Icon: Globe },
|