@commonpub/layer 0.7.7 → 0.7.8
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commonpub/layer",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"files": [
|
|
@@ -51,15 +51,15 @@
|
|
|
51
51
|
"vue-router": "^4.3.0",
|
|
52
52
|
"zod": "^4.3.6",
|
|
53
53
|
"@commonpub/auth": "0.5.0",
|
|
54
|
-
"@commonpub/
|
|
54
|
+
"@commonpub/docs": "0.6.2",
|
|
55
55
|
"@commonpub/config": "0.9.0",
|
|
56
|
+
"@commonpub/editor": "0.7.1",
|
|
56
57
|
"@commonpub/explainer": "0.7.4",
|
|
57
|
-
"@commonpub/docs": "0.6.2",
|
|
58
58
|
"@commonpub/learning": "0.5.0",
|
|
59
|
-
"@commonpub/protocol": "0.9.7",
|
|
60
59
|
"@commonpub/schema": "0.9.4",
|
|
61
|
-
"@commonpub/
|
|
62
|
-
"@commonpub/ui": "0.8.5"
|
|
60
|
+
"@commonpub/protocol": "0.9.7",
|
|
61
|
+
"@commonpub/ui": "0.8.5",
|
|
62
|
+
"@commonpub/server": "2.27.6"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@testing-library/jest-dom": "^6.9.1",
|
|
@@ -476,6 +476,22 @@ async function createVersion(): Promise<void> {
|
|
|
476
476
|
</NuxtLink>
|
|
477
477
|
<span class="cpub-docs-topbar-title">{{ site?.name ?? 'Docs' }}</span>
|
|
478
478
|
<div class="cpub-docs-topbar-spacer" />
|
|
479
|
+
<button
|
|
480
|
+
class="cpub-docs-toolbar-btn"
|
|
481
|
+
title="Undo (Ctrl+Z)"
|
|
482
|
+
:disabled="!blockEditor.canUndo.value"
|
|
483
|
+
@click="blockEditor.undo()"
|
|
484
|
+
>
|
|
485
|
+
<i class="fa-solid fa-rotate-left" />
|
|
486
|
+
</button>
|
|
487
|
+
<button
|
|
488
|
+
class="cpub-docs-toolbar-btn"
|
|
489
|
+
title="Redo (Ctrl+Shift+Z)"
|
|
490
|
+
:disabled="!blockEditor.canRedo.value"
|
|
491
|
+
@click="blockEditor.redo()"
|
|
492
|
+
>
|
|
493
|
+
<i class="fa-solid fa-rotate-right" />
|
|
494
|
+
</button>
|
|
479
495
|
<button
|
|
480
496
|
v-if="selectedPageId"
|
|
481
497
|
class="cpub-docs-toolbar-btn"
|
|
@@ -404,6 +404,24 @@ async function handleUrlImport(result: ImportedContent): Promise<void> {
|
|
|
404
404
|
<i class="fa-solid fa-exclamation-triangle"></i> Save failed
|
|
405
405
|
</span>
|
|
406
406
|
</div>
|
|
407
|
+
<div v-if="!isExplainer" class="cpub-topbar-undo-redo">
|
|
408
|
+
<button
|
|
409
|
+
class="cpub-topbar-icon-btn"
|
|
410
|
+
title="Undo (Ctrl+Z)"
|
|
411
|
+
:disabled="!blockEditor.canUndo.value"
|
|
412
|
+
@click="blockEditor.undo()"
|
|
413
|
+
>
|
|
414
|
+
<i class="fa-solid fa-rotate-left"></i>
|
|
415
|
+
</button>
|
|
416
|
+
<button
|
|
417
|
+
class="cpub-topbar-icon-btn"
|
|
418
|
+
title="Redo (Ctrl+Shift+Z)"
|
|
419
|
+
:disabled="!blockEditor.canRedo.value"
|
|
420
|
+
@click="blockEditor.redo()"
|
|
421
|
+
>
|
|
422
|
+
<i class="fa-solid fa-rotate-right"></i>
|
|
423
|
+
</button>
|
|
424
|
+
</div>
|
|
407
425
|
<div class="cpub-mode-tabs">
|
|
408
426
|
<button :class="['cpub-mode-tab', { active: mode === 'write' }]" @click="mode = 'write'">Write</button>
|
|
409
427
|
<button :class="['cpub-mode-tab', { active: mode === 'preview' }]" @click="enterPreview">Preview</button>
|
|
@@ -619,6 +637,37 @@ async function handleUrlImport(result: ImportedContent): Promise<void> {
|
|
|
619
637
|
.cpub-autosave-status--saved { color: var(--green); }
|
|
620
638
|
.cpub-autosave-status--error { color: var(--red); }
|
|
621
639
|
|
|
640
|
+
.cpub-topbar-undo-redo {
|
|
641
|
+
display: flex;
|
|
642
|
+
align-items: center;
|
|
643
|
+
gap: 2px;
|
|
644
|
+
margin-right: 4px;
|
|
645
|
+
flex-shrink: 0;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.cpub-topbar-icon-btn {
|
|
649
|
+
width: 30px;
|
|
650
|
+
height: 30px;
|
|
651
|
+
display: flex;
|
|
652
|
+
align-items: center;
|
|
653
|
+
justify-content: center;
|
|
654
|
+
background: none;
|
|
655
|
+
border: var(--border-width-default) solid transparent;
|
|
656
|
+
color: var(--text-dim);
|
|
657
|
+
cursor: pointer;
|
|
658
|
+
font-size: 12px;
|
|
659
|
+
padding: 0;
|
|
660
|
+
}
|
|
661
|
+
.cpub-topbar-icon-btn:hover:not(:disabled) {
|
|
662
|
+
background: var(--surface2);
|
|
663
|
+
border-color: var(--border2);
|
|
664
|
+
color: var(--text);
|
|
665
|
+
}
|
|
666
|
+
.cpub-topbar-icon-btn:disabled {
|
|
667
|
+
opacity: 0.3;
|
|
668
|
+
cursor: not-allowed;
|
|
669
|
+
}
|
|
670
|
+
|
|
622
671
|
.cpub-mode-tabs {
|
|
623
672
|
display: flex;
|
|
624
673
|
background: var(--surface2);
|
|
@@ -736,6 +785,7 @@ async function handleUrlImport(result: ImportedContent): Promise<void> {
|
|
|
736
785
|
.cpub-editor-back { margin-left: 0; }
|
|
737
786
|
.cpub-topbar-title-input { max-width: none; font-size: 12px; padding: 3px 6px; }
|
|
738
787
|
.cpub-autosave-status { display: none; }
|
|
788
|
+
.cpub-topbar-undo-redo { display: none; }
|
|
739
789
|
.cpub-mode-tabs { margin: 0 6px; padding: 1px; }
|
|
740
790
|
.cpub-mode-tab { padding: 4px 10px; font-size: 10px; }
|
|
741
791
|
.cpub-topbar-spacer { display: none; }
|
|
@@ -3,11 +3,13 @@ import { contentItems, users } from '@commonpub/schema';
|
|
|
3
3
|
import { eq, and, isNull } from 'drizzle-orm';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* URI: /u/{username}/{type}/{slug}
|
|
6
|
+
* Middleware: serve ActivityPub Article JSON-LD for content URIs.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Matches /u/{username}/{type}/{slug} with AP Accept headers.
|
|
9
|
+
* Non-AP requests pass through to the Nuxt page renderer.
|
|
10
|
+
*
|
|
11
|
+
* This MUST be a middleware (not a server route) because a server route
|
|
12
|
+
* returning undefined sends HTTP 204, which prevents the Nuxt page from rendering.
|
|
11
13
|
*/
|
|
12
14
|
export default defineEventHandler(async (event) => {
|
|
13
15
|
const accept = getRequestHeader(event, 'accept') ?? '';
|
|
@@ -17,12 +19,14 @@ export default defineEventHandler(async (event) => {
|
|
|
17
19
|
|
|
18
20
|
if (!isAPRequest) return;
|
|
19
21
|
|
|
22
|
+
const path = getRequestURL(event).pathname;
|
|
23
|
+
const match = path.match(/^\/u\/([a-zA-Z0-9_-]+)\/([a-z]+)\/([a-z0-9][a-z0-9_-]*)$/);
|
|
24
|
+
if (!match) return;
|
|
25
|
+
|
|
20
26
|
const config = useConfig();
|
|
21
27
|
if (!config.features.federation) return;
|
|
22
28
|
|
|
23
|
-
const username =
|
|
24
|
-
const type = getRouterParam(event, 'type');
|
|
25
|
-
const slug = getRouterParam(event, 'slug');
|
|
29
|
+
const [, username, type, slug] = match;
|
|
26
30
|
if (!username || !type || !slug) return;
|
|
27
31
|
|
|
28
32
|
const db = useDB();
|
|
@@ -51,7 +55,7 @@ export default defineEventHandler(async (event) => {
|
|
|
51
55
|
|
|
52
56
|
setResponseHeader(event, 'content-type', 'application/activity+json');
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
return contentToArticle(
|
|
55
59
|
{
|
|
56
60
|
id: row.content.id,
|
|
57
61
|
type: row.content.type,
|
|
@@ -68,6 +72,4 @@ export default defineEventHandler(async (event) => {
|
|
|
68
72
|
{ username: row.author.username, displayName: row.author.displayName ?? row.author.username },
|
|
69
73
|
domain,
|
|
70
74
|
);
|
|
71
|
-
|
|
72
|
-
return article;
|
|
73
75
|
});
|