@commonpub/layer 0.1.3 → 0.2.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.
@@ -18,16 +18,23 @@ export function useMirrorContent(fedContent: Ref<Record<string, unknown> | null>
18
18
 
19
19
  const title = (fc.title as string) || 'Untitled';
20
20
 
21
- // Parse block content: may be BlockTuple JSON or raw HTML from federation
22
- let content: unknown = fc.content;
23
- if (typeof content === 'string') {
24
- const trimmed = content.trim();
25
- if (trimmed.startsWith('[[') || trimmed.startsWith('[["')) {
26
- try { content = JSON.parse(trimmed); } catch { /* keep as string */ }
27
- }
28
- // If still a string (HTML from federation), wrap as BlockTuple array
29
- if (typeof content === 'string' && content.trim()) {
30
- content = [['paragraph', { html: content }]];
21
+ // Parse block content: prefer cpub:blocks (full fidelity from CommonPub instances),
22
+ // fall back to HTML content (from non-CommonPub instances or legacy federation)
23
+ let content: unknown;
24
+ if (Array.isArray(fc.cpubBlocks) && fc.cpubBlocks.length > 0) {
25
+ // CommonPub→CommonPub: original block structure preserved
26
+ content = fc.cpubBlocks;
27
+ } else {
28
+ content = fc.content;
29
+ if (typeof content === 'string') {
30
+ const trimmed = content.trim();
31
+ if (trimmed.startsWith('[[') || trimmed.startsWith('[["')) {
32
+ try { content = JSON.parse(trimmed); } catch { /* keep as string */ }
33
+ }
34
+ // If still a string (HTML from federation), wrap as BlockTuple array
35
+ if (typeof content === 'string' && content.trim()) {
36
+ content = [['paragraph', { html: content }]];
37
+ }
31
38
  }
32
39
  }
33
40
 
@@ -76,16 +83,6 @@ export function useMirrorContent(fedContent: Ref<Record<string, unknown> | null>
76
83
  } satisfies ContentViewData;
77
84
  });
78
85
 
79
- const viewComponent = computed(() => {
80
- switch (contentType.value) {
81
- case 'article': return resolveComponent('ViewsArticleView');
82
- case 'blog': return resolveComponent('ViewsBlogView');
83
- case 'explainer': return resolveComponent('ViewsExplainerView');
84
- case 'project': return resolveComponent('ViewsProjectView');
85
- default: return null;
86
- }
87
- });
88
-
89
86
  const originDomain = computed(() => (fedContent.value?.originDomain as string) || 'unknown');
90
87
  const originUrl = computed(() => (fedContent.value?.url as string) || null);
91
88
  const authorHandle = computed(() => {
@@ -97,7 +94,6 @@ export function useMirrorContent(fedContent: Ref<Record<string, unknown> | null>
97
94
  contentType,
98
95
  actor,
99
96
  transformedContent,
100
- viewComponent,
101
97
  originDomain,
102
98
  originUrl,
103
99
  authorHandle,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commonpub/layer",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "./nuxt.config.ts",
6
6
  "files": [
@@ -45,15 +45,15 @@
45
45
  "vue": "^3.4.0",
46
46
  "vue-router": "^4.3.0",
47
47
  "zod": "^4.3.6",
48
+ "@commonpub/auth": "0.5.0",
48
49
  "@commonpub/config": "0.7.0",
49
50
  "@commonpub/docs": "0.5.0",
50
- "@commonpub/auth": "0.5.0",
51
51
  "@commonpub/editor": "0.5.0",
52
52
  "@commonpub/learning": "0.5.0",
53
- "@commonpub/server": "2.6.0",
54
- "@commonpub/protocol": "0.9.3",
55
- "@commonpub/ui": "0.7.1",
56
- "@commonpub/schema": "0.8.7"
53
+ "@commonpub/protocol": "0.9.4",
54
+ "@commonpub/schema": "0.8.8",
55
+ "@commonpub/server": "2.7.0",
56
+ "@commonpub/ui": "0.7.1"
57
57
  },
58
58
  "scripts": {}
59
59
  }
@@ -57,16 +57,7 @@ const enrichedContent = computed(() => {
57
57
  return { ...content.value, readTime: readTime.value };
58
58
  });
59
59
 
60
- // Map content types to specialized view components
61
- const viewComponent = computed(() => {
62
- switch (contentType.value) {
63
- case 'article': return resolveComponent('ViewsArticleView');
64
- case 'blog': return resolveComponent('ViewsBlogView');
65
- case 'explainer': return resolveComponent('ViewsExplainerView');
66
- case 'project': return resolveComponent('ViewsProjectView');
67
- default: return null;
68
- }
69
- });
60
+ // Content type used for conditional view component rendering in template
70
61
 
71
62
  // Related content
72
63
  const { data: related } = await useFetch<PaginatedResponse<Serialized<ContentListItem>>>('/api/content', {
@@ -91,12 +82,11 @@ onMounted(() => {
91
82
  </NuxtLink>
92
83
  </div>
93
84
 
94
- <!-- Specialized view -->
95
- <component
96
- v-if="viewComponent && typeof viewComponent !== 'string'"
97
- :is="viewComponent"
98
- :content="enrichedContent"
99
- />
85
+ <!-- Specialized view by content type -->
86
+ <ViewsProjectView v-if="contentType === 'project'" :content="(enrichedContent as any)" />
87
+ <ViewsArticleView v-else-if="contentType === 'article'" :content="(enrichedContent as any)" />
88
+ <ViewsBlogView v-else-if="contentType === 'blog'" :content="(enrichedContent as any)" />
89
+ <ViewsExplainerView v-else-if="contentType === 'explainer'" :content="(enrichedContent as any)" />
100
90
 
101
91
  <!-- Fallback: generic view for unknown types -->
102
92
  <article v-else class="cpub-view">
@@ -7,8 +7,8 @@ const id = route.params.id as string;
7
7
  const { data: fedContent, error, pending } = await useFetch<Record<string, unknown>>(`/api/federation/content/${id}`);
8
8
 
9
9
  const {
10
+ contentType,
10
11
  transformedContent,
11
- viewComponent,
12
12
  originDomain,
13
13
  originUrl,
14
14
  authorHandle,
@@ -51,15 +51,13 @@ useSeoMeta({
51
51
  </div>
52
52
  </div>
53
53
 
54
- <!-- Reuse existing content view component -->
55
- <component
56
- v-if="viewComponent && typeof viewComponent !== 'string'"
57
- :is="viewComponent"
58
- :content="transformedContent"
59
- :federated-id="id"
60
- />
54
+ <!-- Reuse existing content view components by type -->
55
+ <ViewsProjectView v-if="contentType === 'project'" :content="transformedContent" :federated-id="id" />
56
+ <ViewsArticleView v-else-if="contentType === 'article'" :content="transformedContent" :federated-id="id" />
57
+ <ViewsBlogView v-else-if="contentType === 'blog'" :content="transformedContent" :federated-id="id" />
58
+ <ViewsExplainerView v-else-if="contentType === 'explainer'" :content="transformedContent" :federated-id="id" />
61
59
 
62
- <!-- Fallback for non-CommonPub content -->
60
+ <!-- Fallback for non-CommonPub content (Mastodon notes, Lemmy posts, etc.) -->
63
61
  <article v-else class="cpub-mirror-fallback">
64
62
  <div class="cpub-mirror-container">
65
63
  <img v-if="transformedContent.coverImageUrl" :src="transformedContent.coverImageUrl" :alt="transformedContent.title" class="cpub-mirror-cover" />