sequoia-cli 0.4.0-alpha.0 → 0.5.0-alpha.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.
- package/dist/components/sequoia-comments.js +58 -57
- package/dist/index.js +51 -14
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* Attributes:
|
|
15
15
|
* - document-uri: AT Protocol URI for the document (optional if link tag exists)
|
|
16
16
|
* - depth: Maximum depth of nested replies to fetch (default: 6)
|
|
17
|
+
* - hide: Set to "auto" to hide if no document link is detected
|
|
17
18
|
*
|
|
18
19
|
* CSS Custom Properties:
|
|
19
20
|
* - --sequoia-fg-color: Text color (default: #1f2937)
|
|
@@ -573,13 +574,25 @@ const BaseElement = typeof HTMLElement !== "undefined" ? HTMLElement : class {};
|
|
|
573
574
|
class SequoiaComments extends BaseElement {
|
|
574
575
|
constructor() {
|
|
575
576
|
super();
|
|
576
|
-
|
|
577
|
+
const shadow = this.attachShadow({ mode: "open" });
|
|
578
|
+
|
|
579
|
+
const styleTag = document.createElement("style");
|
|
580
|
+
shadow.appendChild(styleTag);
|
|
581
|
+
styleTag.innerText = styles;
|
|
582
|
+
|
|
583
|
+
const container = document.createElement("div");
|
|
584
|
+
shadow.appendChild(container);
|
|
585
|
+
container.className = "sequoia-comments-container";
|
|
586
|
+
container.part = "container";
|
|
587
|
+
|
|
588
|
+
this.commentsContainer = container;
|
|
577
589
|
this.state = { type: "loading" };
|
|
578
590
|
this.abortController = null;
|
|
591
|
+
|
|
579
592
|
}
|
|
580
593
|
|
|
581
594
|
static get observedAttributes() {
|
|
582
|
-
return ["document-uri", "depth"];
|
|
595
|
+
return ["document-uri", "depth", "hide"];
|
|
583
596
|
}
|
|
584
597
|
|
|
585
598
|
connectedCallback() {
|
|
@@ -616,6 +629,11 @@ class SequoiaComments extends BaseElement {
|
|
|
616
629
|
return depthAttr ? parseInt(depthAttr, 10) : 6;
|
|
617
630
|
}
|
|
618
631
|
|
|
632
|
+
get hide() {
|
|
633
|
+
const hideAttr = this.getAttribute("hide");
|
|
634
|
+
return hideAttr === "auto";
|
|
635
|
+
}
|
|
636
|
+
|
|
619
637
|
async loadComments() {
|
|
620
638
|
// Cancel any in-flight request
|
|
621
639
|
this.abortController?.abort();
|
|
@@ -666,68 +684,54 @@ class SequoiaComments extends BaseElement {
|
|
|
666
684
|
}
|
|
667
685
|
|
|
668
686
|
render() {
|
|
669
|
-
const styleTag = `<style>${styles}</style>`;
|
|
670
|
-
|
|
671
687
|
switch (this.state.type) {
|
|
672
688
|
case "loading":
|
|
673
|
-
this.
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
<span class="sequoia-loading-spinner"></span>
|
|
678
|
-
Loading comments...
|
|
679
|
-
</div>
|
|
689
|
+
this.commentsContainer.innerHTML = `
|
|
690
|
+
<div class="sequoia-loading">
|
|
691
|
+
<span class="sequoia-loading-spinner"></span>
|
|
692
|
+
Loading comments...
|
|
680
693
|
</div>
|
|
681
694
|
`;
|
|
682
695
|
break;
|
|
683
696
|
|
|
684
697
|
case "no-document":
|
|
685
|
-
this.
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
<div class="sequoia-warning">
|
|
689
|
-
No document found. Add a <code><link rel="site.standard.document" href="at://..."></code> tag to your page.
|
|
690
|
-
</div>
|
|
698
|
+
this.commentsContainer.innerHTML = `
|
|
699
|
+
<div class="sequoia-warning">
|
|
700
|
+
No document found. Add a <code><link rel="site.standard.document" href="at://..."></code> tag to your page.
|
|
691
701
|
</div>
|
|
692
702
|
`;
|
|
703
|
+
if (this.hide) {
|
|
704
|
+
this.commentsContainer.style.display = 'none';
|
|
705
|
+
}
|
|
693
706
|
break;
|
|
694
707
|
|
|
695
708
|
case "no-comments-enabled":
|
|
696
|
-
this.
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
<div class="sequoia-empty">
|
|
700
|
-
Comments are not enabled for this post.
|
|
701
|
-
</div>
|
|
709
|
+
this.commentsContainer.innerHTML = `
|
|
710
|
+
<div class="sequoia-empty">
|
|
711
|
+
Comments are not enabled for this post.
|
|
702
712
|
</div>
|
|
703
713
|
`;
|
|
704
714
|
break;
|
|
705
715
|
|
|
706
716
|
case "empty":
|
|
707
|
-
this.
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
<
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
<div class="sequoia-empty">
|
|
718
|
-
No comments yet. Be the first to reply on Bluesky!
|
|
719
|
-
</div>
|
|
717
|
+
this.commentsContainer.innerHTML = `
|
|
718
|
+
<div class="sequoia-comments-header">
|
|
719
|
+
<h3 class="sequoia-comments-title">Comments</h3>
|
|
720
|
+
<a href="${this.state.postUrl}" target="_blank" rel="noopener noreferrer" class="sequoia-reply-button">
|
|
721
|
+
${BLUESKY_ICON}
|
|
722
|
+
Reply on Bluesky
|
|
723
|
+
</a>
|
|
724
|
+
</div>
|
|
725
|
+
<div class="sequoia-empty">
|
|
726
|
+
No comments yet. Be the first to reply on Bluesky!
|
|
720
727
|
</div>
|
|
721
728
|
`;
|
|
722
729
|
break;
|
|
723
730
|
|
|
724
731
|
case "error":
|
|
725
|
-
this.
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
<div class="sequoia-error">
|
|
729
|
-
Failed to load comments: ${escapeHtml(this.state.message)}
|
|
730
|
-
</div>
|
|
732
|
+
this.commentsContainer.innerHTML = `
|
|
733
|
+
<div class="sequoia-error">
|
|
734
|
+
Failed to load comments: ${escapeHtml(this.state.message)}
|
|
731
735
|
</div>
|
|
732
736
|
`;
|
|
733
737
|
break;
|
|
@@ -740,19 +744,16 @@ class SequoiaComments extends BaseElement {
|
|
|
740
744
|
.join("");
|
|
741
745
|
const commentCount = this.countComments(replies);
|
|
742
746
|
|
|
743
|
-
this.
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
<
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
<div class="sequoia-comments-list">
|
|
754
|
-
${threadsHtml}
|
|
755
|
-
</div>
|
|
747
|
+
this.commentsContainer.innerHTML = `
|
|
748
|
+
<div class="sequoia-comments-header">
|
|
749
|
+
<h3 class="sequoia-comments-title">${commentCount} Comment${commentCount !== 1 ? "s" : ""}</h3>
|
|
750
|
+
<a href="${this.state.postUrl}" target="_blank" rel="noopener noreferrer" class="sequoia-reply-button">
|
|
751
|
+
${BLUESKY_ICON}
|
|
752
|
+
Reply on Bluesky
|
|
753
|
+
</a>
|
|
754
|
+
</div>
|
|
755
|
+
<div class="sequoia-comments-list">
|
|
756
|
+
${threadsHtml}
|
|
756
757
|
</div>
|
|
757
758
|
`;
|
|
758
759
|
break;
|
|
@@ -800,9 +801,9 @@ class SequoiaComments extends BaseElement {
|
|
|
800
801
|
* Render a single comment
|
|
801
802
|
* @param {any} post - Post data
|
|
802
803
|
* @param {boolean} showThreadLine - Whether to show the connecting thread line
|
|
803
|
-
* @param {number}
|
|
804
|
+
* @param {number} _index - Index in the flattened thread (0 = top-level)
|
|
804
805
|
*/
|
|
805
|
-
renderComment(post, showThreadLine = false,
|
|
806
|
+
renderComment(post, showThreadLine = false, _index = 0) {
|
|
806
807
|
const author = post.author;
|
|
807
808
|
const displayName = author.displayName || author.handle;
|
|
808
809
|
const avatarHtml = author.avatar
|
package/dist/index.js
CHANGED
|
@@ -93241,8 +93241,8 @@ ${l}
|
|
|
93241
93241
|
} }).prompt();
|
|
93242
93242
|
|
|
93243
93243
|
// src/commands/add.ts
|
|
93244
|
-
import { fileURLToPath } from "url";
|
|
93245
|
-
import { dirname as dirname2 } from "path";
|
|
93244
|
+
import { fileURLToPath } from "node:url";
|
|
93245
|
+
import { dirname as dirname2 } from "node:path";
|
|
93246
93246
|
|
|
93247
93247
|
// src/lib/config.ts
|
|
93248
93248
|
import * as fs from "node:fs/promises";
|
|
@@ -93326,6 +93326,9 @@ function generateConfigTemplate(options) {
|
|
|
93326
93326
|
if (options.stripDatePrefix) {
|
|
93327
93327
|
config.stripDatePrefix = options.stripDatePrefix;
|
|
93328
93328
|
}
|
|
93329
|
+
if (options.pathTemplate) {
|
|
93330
|
+
config.pathTemplate = options.pathTemplate;
|
|
93331
|
+
}
|
|
93329
93332
|
if (options.textContentField) {
|
|
93330
93333
|
config.textContentField = options.textContentField;
|
|
93331
93334
|
}
|
|
@@ -99201,6 +99204,32 @@ function getSlugFromOptions(relativePath, rawFrontmatter, options = {}) {
|
|
|
99201
99204
|
}
|
|
99202
99205
|
return slug;
|
|
99203
99206
|
}
|
|
99207
|
+
function resolvePathTemplate(template, post) {
|
|
99208
|
+
const publishDate = new Date(post.frontmatter.publishDate);
|
|
99209
|
+
const year = String(publishDate.getFullYear());
|
|
99210
|
+
const month = String(publishDate.getMonth() + 1).padStart(2, "0");
|
|
99211
|
+
const day = String(publishDate.getDate()).padStart(2, "0");
|
|
99212
|
+
const slugifiedTitle = (post.frontmatter.title || "").toLowerCase().replace(/\s+/g, "-").replace(/[^\w-]/g, "");
|
|
99213
|
+
let result = template.replace(/\{slug\}/g, post.slug).replace(/\{year\}/g, year).replace(/\{month\}/g, month).replace(/\{day\}/g, day).replace(/\{title\}/g, slugifiedTitle);
|
|
99214
|
+
result = result.replace(/\{(\w+)\}/g, (_match, field) => {
|
|
99215
|
+
const value = post.rawFrontmatter[field];
|
|
99216
|
+
if (value != null && typeof value === "string") {
|
|
99217
|
+
return value;
|
|
99218
|
+
}
|
|
99219
|
+
return "";
|
|
99220
|
+
});
|
|
99221
|
+
if (!result.startsWith("/")) {
|
|
99222
|
+
result = `/${result}`;
|
|
99223
|
+
}
|
|
99224
|
+
return result;
|
|
99225
|
+
}
|
|
99226
|
+
function resolvePostPath(post, pathPrefix, pathTemplate) {
|
|
99227
|
+
if (pathTemplate) {
|
|
99228
|
+
return resolvePathTemplate(pathTemplate, post);
|
|
99229
|
+
}
|
|
99230
|
+
const prefix = pathPrefix || "/posts";
|
|
99231
|
+
return `${prefix}/${post.slug}`;
|
|
99232
|
+
}
|
|
99204
99233
|
async function getContentHash(content) {
|
|
99205
99234
|
const encoder = new TextEncoder;
|
|
99206
99235
|
const data = encoder.encode(content);
|
|
@@ -99436,7 +99465,7 @@ async function getOAuthClient() {
|
|
|
99436
99465
|
clientMetadata: {
|
|
99437
99466
|
client_id: `http://localhost?${clientIdParams.toString()}`,
|
|
99438
99467
|
client_name: "Sequoia CLI",
|
|
99439
|
-
client_uri: "https://
|
|
99468
|
+
client_uri: "https://sequoia.pub",
|
|
99440
99469
|
redirect_uris: [CALLBACK_URL],
|
|
99441
99470
|
grant_types: ["authorization_code", "refresh_token"],
|
|
99442
99471
|
response_types: ["code"],
|
|
@@ -99603,8 +99632,7 @@ async function resolveImagePath(ogImage, imagesDir, contentDir) {
|
|
|
99603
99632
|
return null;
|
|
99604
99633
|
}
|
|
99605
99634
|
async function createDocument(agent, post, config, coverImage) {
|
|
99606
|
-
const
|
|
99607
|
-
const postPath = `${pathPrefix}/${post.slug}`;
|
|
99635
|
+
const postPath = resolvePostPath(post, config.pathPrefix, config.pathTemplate);
|
|
99608
99636
|
const publishDate = new Date(post.frontmatter.publishDate);
|
|
99609
99637
|
let textContent;
|
|
99610
99638
|
if (config.textContentField && post.rawFrontmatter?.[config.textContentField]) {
|
|
@@ -99643,8 +99671,7 @@ async function updateDocument(agent, post, atUri, config, coverImage) {
|
|
|
99643
99671
|
throw new Error(`Invalid atUri format: ${atUri}`);
|
|
99644
99672
|
}
|
|
99645
99673
|
const [, , collection, rkey] = uriMatch;
|
|
99646
|
-
const
|
|
99647
|
-
const postPath = `${pathPrefix}/${post.slug}`;
|
|
99674
|
+
const postPath = resolvePostPath(post, config.pathPrefix, config.pathTemplate);
|
|
99648
99675
|
const publishDate = new Date(post.frontmatter.publishDate);
|
|
99649
99676
|
let textContent;
|
|
99650
99677
|
if (config.textContentField && post.rawFrontmatter?.[config.textContentField]) {
|
|
@@ -100923,9 +100950,14 @@ var publishCommand = import_cmd_ts6.command({
|
|
|
100923
100950
|
long: "dry-run",
|
|
100924
100951
|
short: "n",
|
|
100925
100952
|
description: "Preview what would be published without making changes"
|
|
100953
|
+
}),
|
|
100954
|
+
verbose: import_cmd_ts6.flag({
|
|
100955
|
+
long: "verbose",
|
|
100956
|
+
short: "v",
|
|
100957
|
+
description: "Show more information"
|
|
100926
100958
|
})
|
|
100927
100959
|
},
|
|
100928
|
-
handler: async ({ force, dryRun }) => {
|
|
100960
|
+
handler: async ({ force, dryRun, verbose }) => {
|
|
100929
100961
|
const configPath = await findConfig();
|
|
100930
100962
|
if (!configPath) {
|
|
100931
100963
|
R2.error("No publisher.config.ts found. Run 'publisher init' first.");
|
|
@@ -101056,7 +101088,13 @@ ${postsToPublish.length} posts to publish:
|
|
|
101056
101088
|
}
|
|
101057
101089
|
}
|
|
101058
101090
|
}
|
|
101059
|
-
|
|
101091
|
+
let postUrl = "";
|
|
101092
|
+
if (verbose) {
|
|
101093
|
+
const postPath = resolvePostPath(post, config.pathPrefix, config.pathTemplate);
|
|
101094
|
+
postUrl = `
|
|
101095
|
+
${config.siteUrl}${postPath}`;
|
|
101096
|
+
}
|
|
101097
|
+
R2.message(` ${icon} ${post.frontmatter.title} (${reason})${bskyNote}${postUrl}`);
|
|
101060
101098
|
}
|
|
101061
101099
|
if (dryRun) {
|
|
101062
101100
|
if (blueskyEnabled) {
|
|
@@ -101128,8 +101166,7 @@ Dry run complete. No changes made.`);
|
|
|
101128
101166
|
R2.info(` Post is older than ${maxAgeDays} days, skipping Bluesky post`);
|
|
101129
101167
|
} else {
|
|
101130
101168
|
try {
|
|
101131
|
-
const
|
|
101132
|
-
const canonicalUrl = `${config.siteUrl}${pathPrefix}/${post.slug}`;
|
|
101169
|
+
const canonicalUrl = `${config.siteUrl}${resolvePostPath(post, config.pathPrefix, config.pathTemplate)}`;
|
|
101133
101170
|
bskyPostRef = await createBlueskyPost(agent, {
|
|
101134
101171
|
title: post.frontmatter.title,
|
|
101135
101172
|
description: post.frontmatter.description,
|
|
@@ -101278,10 +101315,9 @@ var syncCommand = import_cmd_ts7.command({
|
|
|
101278
101315
|
stripDatePrefix: config.stripDatePrefix
|
|
101279
101316
|
});
|
|
101280
101317
|
s.stop(`Found ${localPosts.length} local posts`);
|
|
101281
|
-
const pathPrefix = config.pathPrefix || "/posts";
|
|
101282
101318
|
const postsByPath = new Map;
|
|
101283
101319
|
for (const post of localPosts) {
|
|
101284
|
-
const postPath =
|
|
101320
|
+
const postPath = resolvePostPath(post, config.pathPrefix, config.pathTemplate);
|
|
101285
101321
|
postsByPath.set(postPath, post);
|
|
101286
101322
|
}
|
|
101287
101323
|
const state = await loadState(configDir);
|
|
@@ -101460,6 +101496,7 @@ async function updateConfigFlow(config, configPath) {
|
|
|
101460
101496
|
ignore: configUpdated.ignore,
|
|
101461
101497
|
removeIndexFromSlug: configUpdated.removeIndexFromSlug,
|
|
101462
101498
|
stripDatePrefix: configUpdated.stripDatePrefix,
|
|
101499
|
+
pathTemplate: configUpdated.pathTemplate,
|
|
101463
101500
|
textContentField: configUpdated.textContentField,
|
|
101464
101501
|
bluesky: configUpdated.bluesky
|
|
101465
101502
|
});
|
|
@@ -101805,7 +101842,7 @@ Publish evergreen content to the ATmosphere
|
|
|
101805
101842
|
|
|
101806
101843
|
> https://tangled.org/stevedylan.dev/sequoia
|
|
101807
101844
|
`,
|
|
101808
|
-
version: "0.
|
|
101845
|
+
version: "0.5.0-alpha.0",
|
|
101809
101846
|
cmds: {
|
|
101810
101847
|
add: addCommand,
|
|
101811
101848
|
auth: authCommand,
|