pandorga 1.3.2 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 293e08c986e9f718e3d08113723d0a864f93b78f0908b56535242f70799ec9fd
4
- data.tar.gz: 554f716cedf086be7731f34b3a57b88cda2f9417b3776471a1cc64fdc40e5d41
3
+ metadata.gz: 96f8f5df58f08bf4eb331ba41f5c7aed8f7ee086ece304b66d2204974605b6c1
4
+ data.tar.gz: e89377d7e62a3413344af45c3605986436adf161cc263159f607b3bf435631f7
5
5
  SHA512:
6
- metadata.gz: dea631f86129632675aebe0045cba2653f3730548766f90712364439c2dbce08262590253eab01d2014e61e428573021c18567ad4083358fa674bc096e3ca2ff
7
- data.tar.gz: 2999d8cf0260b8bf5c854e58d5dd73bdf5e4afcfc89ca0a20b2ef557e0b64432f95f6683916ed5833d10f79ce1413861b978e5b785fdd53fe4f454aff8950032
6
+ metadata.gz: dd8485b02a4fa87afc5aecd93d6da693d9bc290de094a544a1b5e4b41b856858745616dc4a492b7ab9ba2b7abac6ba75f694d62d52ce0c4ba5d342ceb1834a49
7
+ data.tar.gz: d8399d6a1c4eb8f49a3cbcec382e998280da7d39b6686a23f043a83a97c1626a59c9f471f8e8b7ad8d6bcce42e6a92ed6519242a377ec08dc05e24c55429e1a4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.3.3] — 2026-10-05
4
+
5
+ ### Changed
6
+
7
+ - Home portfolio inventory is an index folio (number, thumb, title, project
8
+ icon) with a borderless specimen; drafting marks stay on the poster only
9
+ - Specimen meta shows project tags instead of label/status
10
+ - Mobile selector strip and session-sticky random specimen pick from 1.3.2
11
+ polish remain
12
+
3
13
  ## [1.3.2] — 2026-10-05
4
14
 
5
15
  ### Fixed
@@ -324,10 +324,9 @@
324
324
  ].join('');
325
325
  }
326
326
 
327
- /* Compact inventory row for the home portfolio bench — thumb + name +
328
- * status only. Field-backed; no tagline or tag cloud.
329
- * When options.selectable is true the row selects the specimen instead
330
- * of navigating; the specimen card itself opens the project. */
327
+ /* Compact inventory row for the home portfolio bench.
328
+ * Desktop: index + thumb + title + project icon. Mobile strip uses the
329
+ * thumb/initial only. Selectable rows update the specimen. */
331
330
  function renderProjectInventoryRow(item, options) {
332
331
  options = options || {};
333
332
  var f = blockFields(item);
@@ -337,6 +336,7 @@
337
336
  var selectable = !!options.selectable;
338
337
  var selected = !!options.selected;
339
338
  var slug = item.slug || f.slug || '';
339
+ var index = options.index;
340
340
 
341
341
  var row = document.createElement('article');
342
342
  row.className = 'home-project-inventory-row group' +
@@ -350,12 +350,19 @@
350
350
  }
351
351
 
352
352
  var media = renderPosterMedia(fm.thumbnail, name);
353
- if (!media && fm.icon) {
354
- media = '<div class="home-project-inventory-mark" aria-hidden="true">' +
355
- '<span class="material-symbols-outlined">' + escapeHtml(fm.icon) + '</span></div>';
353
+ var initial = String(name || '?').charAt(0).toUpperCase();
354
+ if (!media) {
355
+ media = '<div class="home-project-inventory-mark home-project-inventory-mark--initial" aria-hidden="true">' +
356
+ escapeHtml(initial) + '</div>';
356
357
  }
357
358
 
358
359
  var html = '';
360
+ if (index != null && index !== '') {
361
+ var label = String(Number(index));
362
+ if (label.length < 2) label = '0' + label;
363
+ html += '<span class="home-project-inventory-index" aria-hidden="true">' +
364
+ escapeHtml(label) + '</span>';
365
+ }
359
366
  if (media) {
360
367
  html += '<div class="home-project-inventory-media">' + media + '</div>';
361
368
  }
@@ -368,12 +375,14 @@
368
375
  '<a class="ledger-card-stretch" href="' + escapeAttr(href) + '">' +
369
376
  escapeHtml(name) + '</a></h3>';
370
377
  }
371
- var meta = renderMetaStrip([
372
- fm.label ? escapeHtml(fm.label) : '',
373
- fm.status ? '<span class="ledger-status">' + escapeHtml(fm.status) + '</span>' : ''
374
- ]);
375
- if (meta) html += meta;
376
378
  html += '</div>';
379
+ if (fm.icon) {
380
+ html += '<span class="home-project-inventory-glyph material-symbols-outlined" aria-hidden="true">' +
381
+ escapeHtml(fm.icon) + '</span>';
382
+ } else {
383
+ html += '<span class="home-project-inventory-glyph home-project-inventory-glyph--initial" aria-hidden="true">' +
384
+ escapeHtml(initial) + '</span>';
385
+ }
377
386
 
378
387
  row.innerHTML = html;
379
388
  return row;
data/_layouts/home.html CHANGED
@@ -211,13 +211,15 @@ layout: shell
211
211
  var specimenSlot = section.querySelector('[data-home-specimen]');
212
212
  var inventorySlot = section.querySelector('[data-home-inventory]');
213
213
  var systemTagHref = tagHrefFrom(list);
214
- var portfolio = entries.slice(0, limit);
214
+ /* Selector strip is sized for six icon buttons on mobile; take up to
215
+ six projects even when home.limit is lower. */
216
+ var portfolio = entries.slice(0, Math.max(limit, 6));
215
217
  if (!portfolio.length) {
216
218
  runtime.Listing.showErrorState(list, 'Projects could not be loaded right now.');
217
219
  return;
218
220
  }
219
221
  if (!specimenSlot || !inventorySlot) {
220
- fill(list, portfolio, function (entry) {
222
+ fill(list, portfolio.slice(0, limit), function (entry) {
221
223
  return runtime.renderSystemCard(asItem(entry), {
222
224
  href: entry.url || runtime.projectUrl(entry.slug),
223
225
  tagHref: systemTagHref,
@@ -227,9 +229,17 @@ layout: shell
227
229
  return;
228
230
  }
229
231
 
230
- var selectedSlug = portfolio[0].slug;
232
+ var featuredPick = runtime.pickFeatured(portfolio.map(asItem), {
233
+ storageKey: 'home-specimen-slug',
234
+ eligible: function () { return true; }
235
+ });
236
+ var selectedSlug = (featuredPick && featuredPick.slug) || portfolio[0].slug;
231
237
  var inventoryResizeObserver = null;
232
238
 
239
+ function entryBySlug(slug) {
240
+ return portfolio.filter(function (entry) { return entry.slug === slug; })[0] || portfolio[0];
241
+ }
242
+
233
243
  function syncInventoryHeight() {
234
244
  if (!window.matchMedia('(min-width: 900px)').matches) {
235
245
  inventorySlot.style.height = '';
@@ -257,12 +267,15 @@ layout: shell
257
267
 
258
268
  function paintSpecimen(entry) {
259
269
  specimenSlot.innerHTML = '';
270
+ /* No card-level drafting corners / edge tick — markers live on the
271
+ poster plate only, so they do not overlap the image. Meta strip
272
+ is suppressed; tags take that slot below the plate. */
260
273
  specimenSlot.appendChild(runtime.renderSystemCard(asItem(entry), {
261
274
  href: entry.url || runtime.projectUrl(entry.slug),
262
275
  tagHref: systemTagHref,
263
- className: 'home-project-specimen ledger-card--edge-primary',
264
- frameCorners: true,
265
- glyphFallback: true
276
+ className: 'home-project-specimen',
277
+ glyphFallback: true,
278
+ metaParts: []
266
279
  }));
267
280
  var specimen = specimenSlot.querySelector('.home-project-specimen');
268
281
  watchSpecimen(specimen);
@@ -276,10 +289,15 @@ layout: shell
276
289
  function paintInventory() {
277
290
  inventorySlot.hidden = false;
278
291
  inventorySlot.innerHTML = '';
279
- portfolio.forEach(function (entry) {
292
+ inventorySlot.style.setProperty(
293
+ '--home-project-icon-count',
294
+ String(Math.min(portfolio.length, 6) || 1)
295
+ );
296
+ portfolio.forEach(function (entry, i) {
280
297
  var row = runtime.renderProjectInventoryRow(asItem(entry), {
281
298
  selectable: true,
282
- selected: entry.slug === selectedSlug
299
+ selected: entry.slug === selectedSlug,
300
+ index: i + 1
283
301
  });
284
302
  function select() {
285
303
  if (selectedSlug === entry.slug) return;
@@ -303,7 +321,7 @@ layout: shell
303
321
  window.requestAnimationFrame(syncInventoryHeight);
304
322
  }
305
323
 
306
- paintSpecimen(portfolio[0]);
324
+ paintSpecimen(entryBySlug(selectedSlug));
307
325
  paintInventory();
308
326
  window.addEventListener('resize', syncInventoryHeight);
309
327
  return;
@@ -943,11 +943,9 @@ html[data-theme="light"] .home-hero-plate {
943
943
  }
944
944
  }
945
945
 
946
- /* ── Engineering artifacts: specimen + inventory bench ──
947
- 40%/60% split: 16:9 specimen card beside a panel inventory whose height
948
- matches the full specimen. Equal-flex rows; thumbs are full-row-height
949
- 16:9 plates flush left. List click updates the specimen; specimen click
950
- opens the project. */
946
+ /* ── Engineering artifacts: specimen + index folio ──
947
+ 40%/60% split: 16:9 specimen beside a hairline index rail (no grey panel).
948
+ List click updates the specimen; specimen click opens the project. */
951
949
  .home-projects-bench {
952
950
  display: grid;
953
951
  grid-template-columns: minmax(0, 1fr);
@@ -969,14 +967,43 @@ html[data-theme="light"] .home-hero-plate {
969
967
  padding: var(--space-md);
970
968
  max-width: none;
971
969
  width: 100%;
970
+ /* Borderless card: ink frame + drafting corners live on the poster only. */
971
+ border: 0;
972
972
  background: var(--color-panel-contrast);
973
973
  }
974
974
 
975
+ :root:not([data-theme="dark"]) .home-project-specimen,
976
+ html[data-theme="light"] .home-project-specimen,
977
+ [data-theme="dark"] .home-project-specimen {
978
+ border: 0;
979
+ }
980
+
975
981
  .home-project-specimen>.ledger-poster,
976
982
  .home-project-specimen>.projects-plate {
977
983
  width: auto;
978
984
  margin: calc(var(--space-md) * -1) calc(var(--space-md) * -1) 0;
979
985
  aspect-ratio: 16 / 9;
986
+ position: relative;
987
+ }
988
+
989
+ /* Glyph plates have no .ledger-poster::after — mirror the image corners. */
990
+ .home-project-specimen>.projects-plate::after {
991
+ content: "";
992
+ --frame-corner-size: 0.7rem;
993
+ --frame-corner-thickness: 1px;
994
+ position: absolute;
995
+ inset: 0.3rem;
996
+ pointer-events: none;
997
+ z-index: 2;
998
+ background:
999
+ linear-gradient(var(--color-primary), var(--color-primary)) top left / var(--frame-corner-size) var(--frame-corner-thickness) no-repeat,
1000
+ linear-gradient(var(--color-primary), var(--color-primary)) top left / var(--frame-corner-thickness) var(--frame-corner-size) no-repeat,
1001
+ linear-gradient(var(--color-primary), var(--color-primary)) top right / var(--frame-corner-size) var(--frame-corner-thickness) no-repeat,
1002
+ linear-gradient(var(--color-primary), var(--color-primary)) top right / var(--frame-corner-thickness) var(--frame-corner-size) no-repeat,
1003
+ linear-gradient(var(--color-primary), var(--color-primary)) bottom left / var(--frame-corner-size) var(--frame-corner-thickness) no-repeat,
1004
+ linear-gradient(var(--color-primary), var(--color-primary)) bottom left / var(--frame-corner-thickness) var(--frame-corner-size) no-repeat,
1005
+ linear-gradient(var(--color-primary), var(--color-primary)) bottom right / var(--frame-corner-size) var(--frame-corner-thickness) no-repeat,
1006
+ linear-gradient(var(--color-primary), var(--color-primary)) bottom right / var(--frame-corner-thickness) var(--frame-corner-size) no-repeat;
980
1007
  }
981
1008
 
982
1009
  @media (max-width: 899px) {
@@ -984,11 +1011,70 @@ html[data-theme="light"] .home-hero-plate {
984
1011
  display: flex;
985
1012
  flex-direction: column;
986
1013
  align-items: stretch;
1014
+ gap: var(--space-md);
987
1015
  }
988
1016
 
989
1017
  .home-project-specimen {
990
1018
  max-width: none;
991
1019
  }
1020
+
1021
+ /* Icon strip under the specimen: equal buttons spanning the band width. */
1022
+ .home-project-inventory {
1023
+ display: grid;
1024
+ grid-template-columns: repeat(var(--home-project-icon-count, 6), minmax(0, 1fr));
1025
+ gap: var(--space-xs);
1026
+ height: auto !important;
1027
+ min-height: 0;
1028
+ overflow: visible;
1029
+ background: transparent;
1030
+ border: 0;
1031
+ }
1032
+
1033
+ .home-project-inventory-row {
1034
+ display: block;
1035
+ flex: none;
1036
+ min-height: 0;
1037
+ padding: 0;
1038
+ border: 1px solid var(--border-gentle-divider);
1039
+ border-bottom-color: var(--border-gentle-divider);
1040
+ background: var(--color-panel-contrast);
1041
+ aspect-ratio: 1;
1042
+ box-shadow: none;
1043
+ }
1044
+
1045
+ .home-project-inventory-row:last-child {
1046
+ border-bottom: 1px solid var(--border-gentle-divider);
1047
+ }
1048
+
1049
+ .home-project-inventory-index,
1050
+ .home-project-inventory-body,
1051
+ .home-project-inventory-glyph {
1052
+ display: none;
1053
+ }
1054
+
1055
+ .home-project-inventory-media {
1056
+ width: 100%;
1057
+ height: 100%;
1058
+ aspect-ratio: auto;
1059
+ border-right: 0;
1060
+ }
1061
+
1062
+ .home-project-inventory-media .ledger-poster,
1063
+ .home-project-inventory-mark {
1064
+ aspect-ratio: 1;
1065
+ height: 100%;
1066
+ }
1067
+
1068
+ .home-project-inventory-media .ledger-poster::after {
1069
+ display: none;
1070
+ }
1071
+
1072
+ .home-project-inventory-row.is-selected {
1073
+ border-color: var(--color-primary);
1074
+ outline: 1px solid var(--color-primary);
1075
+ outline-offset: -1px;
1076
+ background: var(--color-panel-contrast);
1077
+ }
992
1078
  }
993
1079
 
994
1080
  .home-project-specimen .projects-plate--mark {
@@ -1004,7 +1090,7 @@ html[data-theme="light"] .home-hero-plate {
1004
1090
  }
1005
1091
 
1006
1092
  .home-project-specimen .ledger-meta {
1007
- color: var(--color-on-surface-variant);
1093
+ display: none;
1008
1094
  }
1009
1095
 
1010
1096
  .home-project-specimen .ledger-card-title,
@@ -1035,7 +1121,14 @@ html[data-theme="light"] .home-hero-plate {
1035
1121
  overflow: hidden;
1036
1122
  }
1037
1123
 
1038
- .home-project-specimen .ledger-chip-row,
1124
+ /* Tags replace the old label/status strip; outbound links stay off. */
1125
+ .home-project-specimen .ledger-chip-row {
1126
+ display: flex;
1127
+ flex-wrap: wrap;
1128
+ gap: var(--space-xs);
1129
+ margin: 0;
1130
+ }
1131
+
1039
1132
  .home-project-specimen .ledger-card-links {
1040
1133
  display: none;
1041
1134
  }
@@ -1045,8 +1138,8 @@ html[data-theme="light"] .home-hero-plate {
1045
1138
  flex-direction: column;
1046
1139
  min-width: 0;
1047
1140
  min-height: 0;
1048
- background: var(--color-panel-contrast);
1049
- border: 1px solid var(--border-gentle-divider);
1141
+ background: transparent;
1142
+ border: 0;
1050
1143
  overflow: hidden;
1051
1144
  }
1052
1145
 
@@ -1054,22 +1147,20 @@ html[data-theme="light"] .home-hero-plate {
1054
1147
  position: relative;
1055
1148
  display: flex;
1056
1149
  flex-direction: row;
1057
- align-items: stretch;
1150
+ align-items: center;
1058
1151
  flex: 1 1 0;
1059
1152
  min-height: 0;
1060
- padding: 0;
1061
- gap: 0;
1153
+ gap: var(--space-md);
1154
+ padding: var(--space-sm) var(--space-sm) var(--space-sm) 0;
1155
+ border: 0;
1062
1156
  border-bottom: 1px solid var(--border-gentle-divider);
1157
+ background: transparent;
1063
1158
  cursor: pointer;
1064
1159
  transition: background-color var(--motion-duration-fast) var(--motion-ease-default);
1065
1160
  }
1066
1161
 
1067
1162
  .home-project-inventory-row:last-child {
1068
- border-bottom: none;
1069
- }
1070
-
1071
- .home-project-inventory-row:not(:has(.home-project-inventory-media)) {
1072
- padding: var(--space-sm) var(--space-md);
1163
+ border-bottom: 1px solid var(--border-gentle-divider);
1073
1164
  }
1074
1165
 
1075
1166
  .home-project-inventory-row:hover,
@@ -1080,7 +1171,7 @@ html[data-theme="light"] .home-hero-plate {
1080
1171
 
1081
1172
  .home-project-inventory-row.is-selected {
1082
1173
  background: var(--color-surface-high);
1083
- box-shadow: inset 2px 0 0 var(--color-primary);
1174
+ box-shadow: inset 3px 0 0 var(--color-primary);
1084
1175
  }
1085
1176
 
1086
1177
  .home-band--contrast .home-project-inventory-row:hover,
@@ -1089,19 +1180,33 @@ html[data-theme="light"] .home-hero-plate {
1089
1180
  background: var(--color-surface-high-contrast);
1090
1181
  }
1091
1182
 
1092
- /* Thumb is a full-row-height 16:9 plate, flush to the list's left edge.
1093
- Aspect ratio lives on the media shell so the flex item sizes tightly —
1094
- not on a child that left an empty auto-track beside the poster. */
1183
+ .home-project-inventory-index {
1184
+ flex: 0 0 1.75rem;
1185
+ font-family: var(--font-mono);
1186
+ font-size: var(--type-caption);
1187
+ letter-spacing: 0.04em;
1188
+ color: var(--color-on-surface-variant);
1189
+ line-height: 1;
1190
+ text-align: right;
1191
+ }
1192
+
1193
+ .home-project-inventory-row.is-selected .home-project-inventory-index,
1194
+ .home-project-inventory-row:hover .home-project-inventory-index,
1195
+ .home-project-inventory-row:focus-visible .home-project-inventory-index {
1196
+ color: var(--color-primary);
1197
+ }
1198
+
1095
1199
  .home-project-inventory-media {
1096
1200
  flex: 0 0 auto;
1097
- align-self: stretch;
1201
+ width: 5.5rem;
1202
+ align-self: center;
1098
1203
  height: auto;
1099
1204
  min-width: 0;
1100
1205
  min-height: 0;
1101
1206
  aspect-ratio: 16 / 9;
1102
1207
  overflow: hidden;
1103
1208
  background: var(--color-surface-high);
1104
- border-right: 1px solid var(--border-gentle-subtle);
1209
+ border: 1px solid var(--border-gentle-subtle);
1105
1210
  }
1106
1211
 
1107
1212
  .home-project-inventory-media .ledger-poster,
@@ -1115,8 +1220,7 @@ html[data-theme="light"] .home-hero-plate {
1115
1220
  }
1116
1221
 
1117
1222
  .home-project-inventory-media .ledger-poster::after {
1118
- --frame-corner-size: 0.45rem;
1119
- inset: 0.2rem;
1223
+ display: none;
1120
1224
  }
1121
1225
 
1122
1226
  .home-project-inventory-media .ledger-poster img {
@@ -1133,6 +1237,14 @@ html[data-theme="light"] .home-hero-plate {
1133
1237
  color: var(--color-primary);
1134
1238
  }
1135
1239
 
1240
+ .home-project-inventory-mark--initial {
1241
+ font-family: var(--font-content-title);
1242
+ font-size: var(--type-card);
1243
+ font-weight: var(--weight-title);
1244
+ line-height: 1;
1245
+ color: var(--color-on-surface);
1246
+ }
1247
+
1136
1248
  .home-project-inventory-mark .material-symbols-outlined {
1137
1249
  font-size: 1.25rem;
1138
1250
  }
@@ -1141,10 +1253,10 @@ html[data-theme="light"] .home-hero-plate {
1141
1253
  display: flex;
1142
1254
  flex-direction: column;
1143
1255
  justify-content: center;
1144
- gap: var(--space-2xs);
1256
+ gap: 0;
1145
1257
  flex: 1 1 0;
1146
1258
  min-width: 0;
1147
- padding: var(--space-sm) var(--space-md);
1259
+ padding: 0;
1148
1260
  }
1149
1261
 
1150
1262
  .home-project-inventory-title {
@@ -1168,9 +1280,32 @@ html[data-theme="light"] .home-hero-plate {
1168
1280
  color: var(--color-primary);
1169
1281
  }
1170
1282
 
1171
- .home-project-inventory-row .ledger-meta {
1172
- margin: 0;
1283
+ .home-project-inventory-glyph {
1284
+ flex: 0 0 auto;
1285
+ display: inline-flex;
1286
+ align-items: center;
1287
+ justify-content: center;
1288
+ width: 1.75rem;
1289
+ height: 1.75rem;
1290
+ margin-left: auto;
1173
1291
  color: var(--color-on-surface-variant);
1292
+ font-size: 1.25rem;
1293
+ line-height: 1;
1294
+ }
1295
+
1296
+ .home-project-inventory-glyph--initial {
1297
+ font-family: var(--font-content-title);
1298
+ font-size: var(--type-subtitle);
1299
+ font-weight: var(--weight-title);
1300
+ }
1301
+
1302
+ .home-project-inventory-row.is-selected .home-project-inventory-glyph,
1303
+ .home-project-inventory-row:hover .home-project-inventory-glyph {
1304
+ color: var(--color-primary);
1305
+ }
1306
+
1307
+ .home-project-inventory-row .ledger-meta {
1308
+ display: none;
1174
1309
  }
1175
1310
 
1176
1311
 
@@ -24,7 +24,7 @@ module Pandorga
24
24
 
25
25
  gem "pandorga", "~> 1.3"
26
26
  # Local checkout: gem "pandorga", path: "../pandorga"
27
- # GitHub tag: gem "pandorga", github: "alexandrelheinen/pandorga", tag: "v1.3.2"
27
+ # GitHub tag: gem "pandorga", github: "alexandrelheinen/pandorga", tag: "v1.3.3"
28
28
  gem "csv"
29
29
  gem "base64"
30
30
  RUBY
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pandorga
4
- VERSION = "1.3.2"
4
+ VERSION = "1.3.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pandorga
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Pandorga contributors