@dmthepm/commune 0.5.0 → 0.5.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.
@@ -163,6 +163,14 @@ export declare function loadContentEntries(options?: GraphOptions): Promise<Cont
163
163
  * matters when two pieces of content claim the same name, and is a content bug
164
164
  * either way.
165
165
  */
166
+ /**
167
+ * The key a wikilink is looked up by. Case-folded, and typographic quotes
168
+ * folded to their ASCII forms: a title in frontmatter is written with a
169
+ * straight apostrophe, but by the time the remark plugin sees the link text
170
+ * smartypants has curled it, so `[[Andy's Notes]]` arrived as `Andy’s Notes`
171
+ * and rendered as plain text.
172
+ */
173
+ export declare function linkKey(name: string): string;
166
174
  export declare function buildLinkLookup(entries: ContentEntry[]): Map<string, LinkTarget>;
167
175
  /**
168
176
  * Build the url resolution table: canonical `urlPath` → target.
package/lib/lib/graph.js CHANGED
@@ -243,6 +243,20 @@ export async function loadContentEntries(options = {}) {
243
243
  * matters when two pieces of content claim the same name, and is a content bug
244
244
  * either way.
245
245
  */
246
+ /**
247
+ * The key a wikilink is looked up by. Case-folded, and typographic quotes
248
+ * folded to their ASCII forms: a title in frontmatter is written with a
249
+ * straight apostrophe, but by the time the remark plugin sees the link text
250
+ * smartypants has curled it, so `[[Andy's Notes]]` arrived as `Andy’s Notes`
251
+ * and rendered as plain text.
252
+ */
253
+ export function linkKey(name) {
254
+ return name
255
+ .trim()
256
+ .replace(/[\u2018\u2019\u02BC]/g, "'")
257
+ .replace(/[\u201C\u201D]/g, '"')
258
+ .toLowerCase();
259
+ }
246
260
  export function buildLinkLookup(entries) {
247
261
  const lookup = new Map();
248
262
  for (const entry of entries) {
@@ -252,9 +266,9 @@ export function buildLinkLookup(entries) {
252
266
  urlPath: entry.urlPath,
253
267
  };
254
268
  for (const alias of entry.aliases) {
255
- lookup.set(alias.toLowerCase(), target);
269
+ lookup.set(linkKey(alias), target);
256
270
  }
257
- lookup.set(entry.title.toLowerCase(), target);
271
+ lookup.set(linkKey(entry.title), target);
258
272
  }
259
273
  return lookup;
260
274
  }
@@ -10,7 +10,7 @@
10
10
  * graph core in `src/lib/graph.ts` — not here.
11
11
  */
12
12
  import { visit } from 'unist-util-visit';
13
- import { getLinkLookup } from "./lib/graph.js";
13
+ import { getLinkLookup, linkKey } from "./lib/graph.js";
14
14
  /**
15
15
  * Remark plugin function.
16
16
  *
@@ -49,8 +49,7 @@ export default function remarkWikiLinks({ root } = {}) {
49
49
  }
50
50
  // Resolve WikiLink to URL path
51
51
  const trimmedLinkText = linkText.trim();
52
- const lookupKey = trimmedLinkText.toLowerCase();
53
- const resolved = lookup.get(lookupKey);
52
+ const resolved = lookup.get(linkKey(trimmedLinkText));
54
53
  if (resolved) {
55
54
  // Create a proper link node with correct URL for collection
56
55
  // Add data-collection attribute to identify research links for styling
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dmthepm/commune",
3
3
  "type": "module",
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "description": "An Astro wiki engine with WikiLinks, sliding panes, backlinks and static search, plus a commune CLI that queries the content graph and checks links",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -34,15 +34,16 @@
34
34
  if (note?.isStarred) {
35
35
  // Check if star isn't already there
36
36
  if (!link.querySelector('.star-indicator-inline') && !link.nextElementSibling?.classList?.contains('star-indicator-inline')) {
37
- // Create wrapper to prevent line break between link and star
37
+ // The star must not land on a line of its own, but the link itself
38
+ // has to wrap like any other run of text: a whole-link nowrap
39
+ // pushed long titles onto their own line on phones. A no-break
40
+ // space glues the star to the link's last word and nothing else.
38
41
  const wrapper = document.createElement('span');
39
- wrapper.style.whiteSpace = 'nowrap';
40
- wrapper.style.display = 'inline';
41
42
 
42
43
  // Create star as a separate clickable element (not part of the link)
43
44
  const star = document.createElement('span');
44
45
  star.className = 'star-indicator-inline';
45
- star.textContent = ' ⭐';
46
+ star.textContent = '\u00A0⭐';
46
47
  star.setAttribute('aria-label', 'Top 5% most linked - click to learn more');
47
48
  star.setAttribute('role', 'button');
48
49
  star.setAttribute('tabindex', '0');
@@ -67,7 +68,7 @@
67
68
  }
68
69
  });
69
70
 
70
- // Wrap the link in the nowrap container
71
+ // Keep the link and its star as one span
71
72
  link.parentNode.insertBefore(wrapper, link);
72
73
  wrapper.appendChild(link);
73
74
  wrapper.appendChild(star);