From d483b6e8401cea9659b2388f5746b9a0e22b2a15 Mon Sep 17 00:00:00 2001
From: Kevin Leutzinger <6435727+kleutzinger@users.noreply.github.com>
Date: Tue, 30 Sep 2025 18:50:10 -0400
Subject: [PATCH] add shareHTML relation
---
.../server/src/services/builtin_attributes.ts | 2 ++
packages/share-theme/src/templates/page.ejs | 34 +++++++++++++++++--
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/apps/server/src/services/builtin_attributes.ts b/apps/server/src/services/builtin_attributes.ts
index 2d35992aa..ca48f3df1 100644
--- a/apps/server/src/services/builtin_attributes.ts
+++ b/apps/server/src/services/builtin_attributes.ts
@@ -66,6 +66,7 @@ export default [
{ type: "label", name: "shareDisallowRobotIndexing" },
{ type: "label", name: "shareCredentials" },
{ type: "label", name: "shareIndex" },
+ { type: "label", name: "shareHTMLLocation" },
{ type: "label", name: "displayRelations" },
{ type: "label", name: "hideRelations" },
{ type: "label", name: "titleTemplate", isDangerous: true },
@@ -105,6 +106,7 @@ export default [
{ type: "relation", name: "renderNote", isDangerous: true },
{ type: "relation", name: "shareCss" },
{ type: "relation", name: "shareJs" },
+ { type: "relation", name: "shareHTML" },
{ type: "relation", name: "shareTemplate" },
{ type: "relation", name: "shareFavicon" }
];
diff --git a/packages/share-theme/src/templates/page.ejs b/packages/share-theme/src/templates/page.ejs
index e4ac1f603..eaa7dbe3b 100644
--- a/packages/share-theme/src/templates/page.ejs
+++ b/packages/share-theme/src/templates/page.ejs
@@ -1,7 +1,31 @@
- <% const hasTree = subRoot.note.hasVisibleChildren(); %>
+ <%
+ const hasTree = subRoot.note.hasVisibleChildren();
+
+ // Collect HTML snippets by location
+ const htmlSnippetsByLocation = {};
+ for (const htmlRelation of note.getRelations("shareHTML")) {
+ const htmlNote = htmlRelation.targetNote;
+ if (htmlNote) {
+ let location = htmlNote.getLabelValue("shareHTMLLocation") || "content:end";
+ // Default to :end if no position specified
+ if (!location.includes(":")) {
+ location = location + ":end";
+ }
+ if (!htmlSnippetsByLocation[location]) {
+ htmlSnippetsByLocation[location] = [];
+ }
+ htmlSnippetsByLocation[location].push(htmlNote.getContent());
+ }
+ }
+ const renderSnippets = (location) => {
+ const snippets = htmlSnippetsByLocation[location];
+ return snippets ? snippets.join("\n") : "";
+ };
+ %>
+ <%- renderSnippets("head:start") %>
@@ -53,6 +77,7 @@
+ <%- renderSnippets("head:end") %>
<%
const customLogoId = subRoot.note.getRelation("shareLogo")?.value;
@@ -72,6 +97,7 @@ content = content.replaceAll(headingRe, (...match) => {
});
%>
+<%- renderSnippets("body:start") %>
-
ck-content<% } %><% if (isEmpty) { %> no-content<% } %>">
+ <%- renderSnippets("content:start") %>
<%= note.title %>
<% if (isEmpty && (!note.hasVisibleChildren() && note.type !== "book")) { %>
This note has no content.
@@ -132,6 +158,7 @@ content = content.replaceAll(headingRe, (...match) => {
%>
<%- content %>
<% } %>
+ <%- renderSnippets("content:end") %>
<% if (note.hasVisibleChildren() || note.type === "book") { %>
@@ -164,7 +191,7 @@ content = content.replaceAll(headingRe, (...match) => {
<% } %>
- <% if (hasTree) { %>
+ <% if (hasTree) { %>
<%- include("prev_next", { note: note, subRoot: subRoot }) %>
<% } %>
@@ -205,5 +232,6 @@ content = content.replaceAll(headingRe, (...match) => {
<% } %>
+<%- renderSnippets("body:end") %>