r-markdown-cli 0.1.0 → 0.1.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/dist/cli.js CHANGED
@@ -832,28 +832,68 @@ body[data-rmd-theme] {
832
832
 
833
833
  .rmd-timeline-horizontal ol {
834
834
  display: flex;
835
+ flex-wrap: nowrap;
835
836
  overflow-x: auto;
836
- gap: 20px;
837
- padding-bottom: 10px;
837
+ overflow-y: hidden;
838
+ gap: 24px;
839
+ padding-bottom: 12px;
840
+ /* Treat the ol as a horizontal scroll viewport with explicit snap so
841
+ each @item lines up nicely when the user scrolls. */
842
+ scroll-snap-type: x proximity;
843
+ scrollbar-width: thin;
838
844
  }
839
845
 
840
846
  .rmd-timeline-horizontal .rmd-timeline-item {
841
- flex: 0 0 auto;
842
- min-width: 200px;
847
+ /* Cap each item to a predictable width so a single overflowing item
848
+ can't squeeze siblings out of the visible viewport. Long prose
849
+ wraps inside the box; the user scrolls horizontally to see the
850
+ next item. */
851
+ flex: 0 0 240px;
852
+ width: 240px;
853
+ max-width: 240px;
843
854
  position: relative;
844
855
  padding-top: 28px;
856
+ scroll-snap-align: start;
857
+ /* Prevent runaway content (long URLs, code, CJK without spaces) from
858
+ widening the flex item beyond its declared basis. */
859
+ min-width: 0;
860
+ overflow-wrap: anywhere;
861
+ word-break: break-word;
845
862
  }
846
863
 
847
- .rmd-timeline-horizontal ol::before {
864
+ .rmd-timeline-horizontal .rmd-timeline-content {
865
+ /* Belt-and-suspenders: cap inner content too, in case authors nest
866
+ wide blocks (chart, table) inside a timeline item. */
867
+ max-width: 100%;
868
+ overflow-wrap: anywhere;
869
+ }
870
+
871
+ .rmd-timeline-horizontal .rmd-timeline-content pre,
872
+ .rmd-timeline-horizontal .rmd-timeline-content img,
873
+ .rmd-timeline-horizontal .rmd-timeline-content table {
874
+ max-width: 100%;
875
+ }
876
+
877
+ /* The connector line is drawn per-item (::after) so that it scrolls with
878
+ the items inside the overflow:auto container. The previous ol::before
879
+ approach anchored the line to the visible viewport, which made the
880
+ line stay put while items scrolled past \u2014 broken for any timeline
881
+ wider than the viewport. */
882
+ .rmd-timeline-horizontal .rmd-timeline-item::after {
848
883
  position: absolute;
849
884
  top: 5px;
850
- left: 0;
851
- right: 0;
885
+ left: 6px;
886
+ /* Extend across the 24px gap to meet the next item's dot. */
887
+ right: calc(-24px + 6px);
852
888
  height: 2px;
853
889
  background: var(--rmd-color-line);
854
890
  content: "";
855
891
  }
856
892
 
893
+ .rmd-timeline-horizontal .rmd-timeline-item:last-child::after {
894
+ display: none;
895
+ }
896
+
857
897
  .rmd-timeline-horizontal .rmd-timeline-item::before {
858
898
  position: absolute;
859
899
  top: 0;
@@ -5219,22 +5259,20 @@ function parseTimeline(block2, parseChildren) {
5219
5259
  const { attrs } = parseAttrs(block2.attrText);
5220
5260
  const unknownAttrs = pickUnknownAttrs(attrs, ["direction"]);
5221
5261
  const items = [];
5262
+ const warnings = [];
5222
5263
  let current = null;
5264
+ let hasOrphanContent = false;
5223
5265
  for (const line of block2.content.split(/\r?\n/)) {
5224
- const match2 = line.match(/^@\s+(.*?)(?:\s+\[(.*?)\])?\s*$/);
5266
+ const match2 = line.match(/^\s*@\s+(.+?)\s*$/);
5225
5267
  if (match2) {
5226
5268
  if (current) {
5227
5269
  items.push(current);
5228
5270
  }
5229
- const time = match2[1];
5230
- const attrStr = match2[2] ? `[${match2[2]}]` : "";
5231
- const itemAttrs = {};
5232
- let titleMatch = attrStr.match(/title="([^"]*)"/);
5233
- let statusMatch = attrStr.match(/status="([^"]*)"/);
5271
+ const { time, title, status } = parseTimelineHeader(match2[1]);
5234
5272
  current = {
5235
5273
  time,
5236
- title: titleMatch ? titleMatch[1] : null,
5237
- status: ["success", "warning", "danger", "pending"].includes(statusMatch?.[1]) ? statusMatch[1] : "default",
5274
+ title,
5275
+ status,
5238
5276
  source: ""
5239
5277
  };
5240
5278
  continue;
@@ -5242,12 +5280,20 @@ function parseTimeline(block2, parseChildren) {
5242
5280
  if (current) {
5243
5281
  current.source += `${line}
5244
5282
  `;
5283
+ } else if (line.trim().length > 0) {
5284
+ hasOrphanContent = true;
5245
5285
  }
5246
5286
  }
5247
5287
  if (current) {
5248
5288
  items.push(current);
5249
5289
  }
5250
- return withOptionalFields({
5290
+ if (hasOrphanContent) {
5291
+ warnings.push("timeline-content-before-first-item");
5292
+ }
5293
+ if (items.length === 0) {
5294
+ warnings.push("timeline-empty-items");
5295
+ }
5296
+ return withOptionalFields(withWarnings({
5251
5297
  type: "timeline",
5252
5298
  direction: attrs.direction === "horizontal" ? "horizontal" : "vertical",
5253
5299
  items: items.map((item) => ({
@@ -5256,19 +5302,41 @@ function parseTimeline(block2, parseChildren) {
5256
5302
  status: item.status,
5257
5303
  children: parseChildren(item.source.trim())
5258
5304
  }))
5259
- }, { unknownAttrs });
5305
+ }, warnings), { unknownAttrs });
5306
+ }
5307
+ function parseTimelineHeader(headerText) {
5308
+ const bracketRe = /\s*\[([^\]]*)\]\s*$/;
5309
+ const pairRe = /([a-zA-Z_][a-zA-Z0-9_-]*)\s*=\s*"([^"]*)"/g;
5310
+ const collected = {};
5311
+ let remainder = headerText;
5312
+ while (true) {
5313
+ const m = remainder.match(bracketRe);
5314
+ if (!m) break;
5315
+ for (const pair of m[1].matchAll(pairRe)) {
5316
+ collected[pair[1]] = pair[2];
5317
+ }
5318
+ remainder = remainder.slice(0, m.index);
5319
+ }
5320
+ const status = ["success", "warning", "danger", "pending"].includes(collected.status) ? collected.status : "default";
5321
+ return {
5322
+ time: remainder.trim(),
5323
+ title: typeof collected.title === "string" ? collected.title : null,
5324
+ status
5325
+ };
5260
5326
  }
5261
5327
  function parseKanban(block2, parseChildren) {
5262
5328
  const columns = [];
5329
+ const warnings = [];
5263
5330
  let current = null;
5331
+ let hasOrphanContent = false;
5264
5332
  for (const line of block2.content.split(/\r?\n/)) {
5265
- const match2 = line.match(/^@\s+(.*?)\s*$/);
5333
+ const match2 = line.match(/^\s*@\s+(.+?)\s*$/);
5266
5334
  if (match2) {
5267
5335
  if (current) {
5268
5336
  columns.push(current);
5269
5337
  }
5270
5338
  current = {
5271
- title: match2[1],
5339
+ title: match2[1].trim(),
5272
5340
  source: ""
5273
5341
  };
5274
5342
  continue;
@@ -5276,18 +5344,26 @@ function parseKanban(block2, parseChildren) {
5276
5344
  if (current) {
5277
5345
  current.source += `${line}
5278
5346
  `;
5347
+ } else if (line.trim().length > 0) {
5348
+ hasOrphanContent = true;
5279
5349
  }
5280
5350
  }
5281
5351
  if (current) {
5282
5352
  columns.push(current);
5283
5353
  }
5284
- return {
5354
+ if (hasOrphanContent) {
5355
+ warnings.push("kanban-content-before-first-column");
5356
+ }
5357
+ if (columns.length === 0) {
5358
+ warnings.push("kanban-empty-columns");
5359
+ }
5360
+ return withWarnings({
5285
5361
  type: "kanban",
5286
5362
  columns: columns.map((col) => ({
5287
5363
  title: col.title,
5288
5364
  children: parseChildren(col.source.trim())
5289
5365
  }))
5290
- };
5366
+ }, warnings);
5291
5367
  }
5292
5368
  function parseDetails(block2, parseChildren) {
5293
5369
  const { attrs } = parseAttrs(block2.attrText);
@@ -11975,7 +12051,7 @@ async function createPreviewServer(file, options = {}) {
11975
12051
 
11976
12052
  // packages/cli/src/index.js
11977
12053
  var USAGE = `
11978
- Rich Markdown (rmd) CLI v0.2.0
12054
+ Rich Markdown (rmd) CLI v0.1.2
11979
12055
 
11980
12056
  Usage:
11981
12057
  rmd <command> [options]
@@ -12045,7 +12121,7 @@ async function main(argv = process.argv.slice(2), io = defaultIo()) {
12045
12121
  return 0;
12046
12122
  }
12047
12123
  if (command === "--version" || command === "-v") {
12048
- io.stdout(`rmd v0.2.0
12124
+ io.stdout(`rmd v0.1.2
12049
12125
  `);
12050
12126
  return 0;
12051
12127
  }
@@ -12131,8 +12207,9 @@ function parseInitArgs(args) {
12131
12207
  function resolveSkillSource(platform) {
12132
12208
  const __dirname2 = dirname2(fileURLToPath2(import.meta.url));
12133
12209
  const candidates = [
12134
- resolve2(__dirname2, "../assets/skills", platform),
12135
- resolve2(__dirname2, "../../../skills", platform)
12210
+ resolve2(__dirname2, "../skills", platform),
12211
+ resolve2(__dirname2, "../../../skills", platform),
12212
+ resolve2(__dirname2, "../assets/skills", platform)
12136
12213
  ];
12137
12214
  return candidates.find((candidate) => existsSync(candidate));
12138
12215
  }