Changeset 221a209 in Klonkt
- Timestamp:
- 06/16/2026 08:52:32 PM (3 months ago)
- Branches:
- main
- Children:
- 2248cd2
- Parents:
- fb02cc0
- Location:
- src
- Files:
-
- 5 edited
-
config/database.js (modified) (1 diff)
-
routes/circle.js (modified) (4 diffs)
-
services/CircleFederation.js (modified) (4 diffs)
-
services/CircleService.js (modified) (3 diffs)
-
views/pages/circle-post.ejs (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/config/database.js
rfb02cc0 r221a209 172 172 ); 173 173 `); 174 175 // Tags van de originele post — getoond in de cirkel (comma-separated string). 176 ensureColumn('remote_posts', 'tags', 'TEXT'); 174 177 } 175 178 -
src/routes/circle.js
rfb02cc0 r221a209 30 30 31 31 const rows = db.prepare(` 32 SELECT p.id, p.published, p.title, p.summary, p.media_json, 32 SELECT p.id, p.published, p.title, p.summary, p.media_json, p.tags, 33 33 a.name AS actor_name 34 34 FROM remote_posts p … … 51 51 created_at: r.published, 52 52 type: 'post', 53 tags: '',53 tags: r.tags || '', 54 54 pinned: 0, 55 55 status: 'published', … … 81 81 82 82 const row = db.prepare(` 83 SELECT p.id, p.published, p.title, p.summary, p.url, p.media_json, 83 SELECT p.id, p.published, p.title, p.summary, p.url, p.media_json, p.tags, 84 84 a.name AS actor_name, a.url AS actor_url, a.avatar AS actor_avatar 85 85 FROM remote_posts p … … 100 100 sourceAvatar: safeUrl(row.actor_avatar), 101 101 originalUrl: safeUrl(row.url), 102 tags: (row.tags || '').split(',').map((t) => t.trim()).filter(Boolean), 103 sourceTagBase: safeUrl(row.actor_url) ? safeUrl(row.actor_url).replace(/\/+$/, '') : null, 102 104 }; 103 105 -
src/services/CircleFederation.js
rfb02cc0 r221a209 85 85 } 86 86 87 // Tags-kolom (JSON-array of comma-separated) -> nette string-array. 88 function parseTags(raw) { 89 if (!raw) return []; 90 if (Array.isArray(raw)) return raw.map((t) => String(t).trim()).filter(Boolean); 91 try { const j = JSON.parse(raw); if (Array.isArray(j)) return j.map((t) => String(t).trim()).filter(Boolean); } catch { /* geen JSON */ } 92 return String(raw).split(',').map((t) => t.trim()).filter(Boolean); 93 } 94 87 95 function iso(d) { 88 96 const t = d ? new Date(d) : new Date(); … … 136 144 137 145 const rows = db.prepare(` 138 SELECT slug, title, excerpt, content, cover_image_url, published_at, created_at, type 146 SELECT slug, title, excerpt, content, cover_image_url, published_at, created_at, type, tags 139 147 FROM posts 140 148 WHERE site_id = ? AND status = 'published' … … 148 156 const published = iso(p.published_at || p.created_at); 149 157 const summary = (p.excerpt || stripHtml(p.content)).slice(0, 500); 158 const tags = parseTags(p.tags).slice(0, 12); 150 159 return { 151 160 type: 'Create', … … 161 170 published, 162 171 ...(p.cover_image_url ? { image: { type: 'Image', url: abs(base, p.cover_image_url) } } : {}), 172 // ActivityStreams: tags als Hashtag-objecten (href naar de bron-tagpagina). 173 ...(tags.length ? { tag: tags.map((t) => ({ type: 'Hashtag', name: '#' + String(t).replace(/^#/, ''), href: `${base}/tag/${encodeURIComponent(t)}` })) } : {}), 163 174 }, 164 175 }; -
src/services/CircleService.js
rfb02cc0 r221a209 29 29 function baseOf(remoteUrl) { 30 30 return String(remoteUrl).replace(/\/+$/, ''); 31 } 32 33 // AS Hashtag-array -> comma-separated tagnamen (zonder #), gesanitized. 34 function extractTags(tag) { 35 if (!Array.isArray(tag)) return null; 36 const names = tag 37 .map((t) => String((t && t.name) || '').replace(/^#/, '').trim()) 38 .filter(Boolean) 39 .slice(0, 12); 40 return names.length ? names.join(', ') : null; 31 41 } 32 42 … … 83 93 `), 84 94 upsertPost: db.prepare(` 85 INSERT INTO remote_posts (id, actor_id, published, title, summary, url, media_json, raw_json, fetched_at)86 VALUES (@id, @actor_id, @published, @title, @summary, @url, @media_json, @ raw_json, CURRENT_TIMESTAMP)95 INSERT INTO remote_posts (id, actor_id, published, title, summary, url, media_json, tags, raw_json, fetched_at) 96 VALUES (@id, @actor_id, @published, @title, @summary, @url, @media_json, @tags, @raw_json, CURRENT_TIMESTAMP) 87 97 ON CONFLICT(id) DO UPDATE SET 88 98 published=excluded.published, title=excluded.title, summary=excluded.summary, 89 url=excluded.url, media_json=excluded.media_json, raw_json=excluded.raw_json, fetched_at=CURRENT_TIMESTAMP 99 url=excluded.url, media_json=excluded.media_json, tags=excluded.tags, 100 raw_json=excluded.raw_json, fetched_at=CURRENT_TIMESTAMP 90 101 `), 91 102 }; … … 169 180 url: obj.url || obj.id, 170 181 media_json: media.length ? JSON.stringify(media) : null, 182 tags: extractTags(obj.tag), 171 183 raw_json: JSON.stringify(obj).slice(0, 20000), 172 184 }); -
src/views/pages/circle-post.ejs
rfb02cc0 r221a209 23 23 <div class="cirkel-post-body"><%= post.body %></div> 24 24 25 <% if (post.tags && post.tags.length) { %> 26 <div class="cirkel-post-tags"> 27 <% post.tags.forEach(function(t){ %> 28 <% if (post.sourceTagBase) { %> 29 <a class="cirkel-tag" href="<%= post.sourceTagBase %>/tag/<%= encodeURIComponent(t) %>" target="_blank" rel="noopener">#<%= t %></a> 30 <% } else { %> 31 <span class="cirkel-tag">#<%= t %></span> 32 <% } %> 33 <% }); %> 34 </div> 35 <% } %> 36 25 37 <% if (post.originalUrl) { %> 26 38 <p class="cirkel-post-readmore"> … … 42 54 .cirkel-post-cover { width: 100%; border-radius: var(--radius); margin: 0 0 1.5rem; display: block; } 43 55 .cirkel-post-body { font-size: 1.05rem; line-height: 1.7; white-space: pre-wrap; color: var(--ink); } 56 .cirkel-post-tags { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: 1.25rem; } 57 .cirkel-tag { font-size: .8rem; color: var(--ink-muted); background: var(--paper-2); border: 1px solid var(--rule); border-radius: 999px; padding: .15rem .6rem; text-decoration: none; } 58 .cirkel-tag:hover { border-color: var(--accent); color: var(--accent); } 44 59 .cirkel-post-readmore { margin-top: 2rem; padding-top: 1.25rem; border-top: 1px solid var(--rule); } 45 60 .cirkel-post-readmore a { color: var(--accent); text-decoration: none; font-weight: 600; }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)