Add hide attribute to sequoia-comments component 9ef18c3f
Resolves #1
Heath Stewart · 2026-02-08 01:12 4 file(s) · +114 −124
bun.lock +1 −14
24 24
    },
25 25
    "packages/cli": {
26 26
      "name": "sequoia-cli",
27 -
      "version": "0.3.2",
27 +
      "version": "0.4.0",
28 28
      "bin": {
29 29
        "sequoia": "dist/index.js",
30 30
      },
41 41
      "devDependencies": {
42 42
        "@biomejs/biome": "^2.3.13",
43 43
        "@types/mime-types": "^3.0.1",
44 -
        "@types/node": "^20",
45 -
      },
46 -
      "peerDependencies": {
47 -
        "typescript": "^5",
48 -
      },
49 -
    },
50 -
    "packages/ui": {
51 -
      "name": "sequoia-ui",
52 -
      "version": "0.1.0",
53 -
      "devDependencies": {
54 -
        "@biomejs/biome": "^2.3.13",
55 44
        "@types/node": "^20",
56 45
      },
57 46
      "peerDependencies": {
1369 1358
    "send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="],
1370 1359
1371 1360
    "sequoia-cli": ["sequoia-cli@workspace:packages/cli"],
1372 -
1373 -
    "sequoia-ui": ["sequoia-ui@workspace:packages/ui"],
1374 1361
1375 1362
    "serve-static": ["serve-static@1.16.3", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "~0.19.1" } }, "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA=="],
1376 1363
docs/docs/pages/comments.mdx +1 −0
143 143
|-----------|------|---------|-------------|
144 144
| `document-uri` | `string` | - | AT Protocol URI for the document. Optional if a `<link rel="site.standard.document">` tag exists in the page head. |
145 145
| `depth` | `number` | `6` | Maximum depth of nested replies to fetch. |
146 +
| `hide` | `string` | - | Set to "auto" to hide if no document link is detected |
146 147
147 148
```html
148 149
<!-- Use attributes for explicit control -->
docs/docs/public/sequoia-comments.js +56 −55
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 574
class SequoiaComments extends BaseElement {
574 575
	constructor() {
575 576
		super();
576 -
		this.shadow = this.attachShadow({ mode: "open" });
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() {
614 627
	get depth() {
615 628
		const depthAttr = this.getAttribute("depth");
616 629
		return depthAttr ? parseInt(depthAttr, 10) : 6;
630 +
	}
631 +
632 +
	get hide() {
633 +
		const hideAttr = this.getAttribute("hide");
634 +
		return hideAttr === "auto";
617 635
	}
618 636
619 637
	async loadComments() {
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.shadow.innerHTML = `
674 -
					${styleTag}
675 -
					<div class="sequoia-comments-container">
676 -
						<div class="sequoia-loading">
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.shadow.innerHTML = `
686 -
					${styleTag}
687 -
					<div class="sequoia-comments-container">
688 -
						<div class="sequoia-warning">
689 -
							No document found. Add a <code>&lt;link rel="site.standard.document" href="at://..."&gt;</code> tag to your page.
690 -
						</div>
698 +
				this.commentsContainer.innerHTML = `
699 +
					<div class="sequoia-warning">
700 +
						No document found. Add a <code>&lt;link rel="site.standard.document" href="at://..."&gt;</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.shadow.innerHTML = `
697 -
					${styleTag}
698 -
					<div class="sequoia-comments-container">
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.shadow.innerHTML = `
708 -
					${styleTag}
709 -
					<div class="sequoia-comments-container">
710 -
						<div class="sequoia-comments-header">
711 -
							<h3 class="sequoia-comments-title">Comments</h3>
712 -
							<a href="${this.state.postUrl}" target="_blank" rel="noopener noreferrer" class="sequoia-reply-button">
713 -
								${BLUESKY_ICON}
714 -
								Reply on Bluesky
715 -
							</a>
716 -
						</div>
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.shadow.innerHTML = `
726 -
					${styleTag}
727 -
					<div class="sequoia-comments-container">
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 744
					.join("");
741 745
				const commentCount = this.countComments(replies);
742 746
743 -
				this.shadow.innerHTML = `
744 -
					${styleTag}
745 -
					<div class="sequoia-comments-container">
746 -
						<div class="sequoia-comments-header">
747 -
							<h3 class="sequoia-comments-title">${commentCount} Comment${commentCount !== 1 ? "s" : ""}</h3>
748 -
							<a href="${this.state.postUrl}" target="_blank" rel="noopener noreferrer" class="sequoia-reply-button">
749 -
								${BLUESKY_ICON}
750 -
								Reply on Bluesky
751 -
							</a>
752 -
						</div>
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;
packages/cli/src/components/sequoia-comments.js +56 −55
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 574
class SequoiaComments extends BaseElement {
574 575
	constructor() {
575 576
		super();
576 -
		this.shadow = this.attachShadow({ mode: "open" });
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() {
614 627
	get depth() {
615 628
		const depthAttr = this.getAttribute("depth");
616 629
		return depthAttr ? parseInt(depthAttr, 10) : 6;
630 +
	}
631 +
632 +
	get hide() {
633 +
		const hideAttr = this.getAttribute("hide");
634 +
		return hideAttr === "auto";
617 635
	}
618 636
619 637
	async loadComments() {
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.shadow.innerHTML = `
674 -
					${styleTag}
675 -
					<div class="sequoia-comments-container">
676 -
						<div class="sequoia-loading">
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.shadow.innerHTML = `
686 -
					${styleTag}
687 -
					<div class="sequoia-comments-container">
688 -
						<div class="sequoia-warning">
689 -
							No document found. Add a <code>&lt;link rel="site.standard.document" href="at://..."&gt;</code> tag to your page.
690 -
						</div>
698 +
				this.commentsContainer.innerHTML = `
699 +
					<div class="sequoia-warning">
700 +
						No document found. Add a <code>&lt;link rel="site.standard.document" href="at://..."&gt;</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.shadow.innerHTML = `
697 -
					${styleTag}
698 -
					<div class="sequoia-comments-container">
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.shadow.innerHTML = `
708 -
					${styleTag}
709 -
					<div class="sequoia-comments-container">
710 -
						<div class="sequoia-comments-header">
711 -
							<h3 class="sequoia-comments-title">Comments</h3>
712 -
							<a href="${this.state.postUrl}" target="_blank" rel="noopener noreferrer" class="sequoia-reply-button">
713 -
								${BLUESKY_ICON}
714 -
								Reply on Bluesky
715 -
							</a>
716 -
						</div>
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.shadow.innerHTML = `
726 -
					${styleTag}
727 -
					<div class="sequoia-comments-container">
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 744
					.join("");
741 745
				const commentCount = this.countComments(replies);
742 746
743 -
				this.shadow.innerHTML = `
744 -
					${styleTag}
745 -
					<div class="sequoia-comments-container">
746 -
						<div class="sequoia-comments-header">
747 -
							<h3 class="sequoia-comments-title">${commentCount} Comment${commentCount !== 1 ? "s" : ""}</h3>
748 -
							<a href="${this.state.postUrl}" target="_blank" rel="noopener noreferrer" class="sequoia-reply-button">
749 -
								${BLUESKY_ICON}
750 -
								Reply on Bluesky
751 -
							</a>
752 -
						</div>
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;