@commonpub/layer 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.
- package/package.json +6 -6
- package/pages/docs/[siteSlug]/edit.vue +199 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commonpub/layer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"files": [
|
|
@@ -51,14 +51,14 @@
|
|
|
51
51
|
"vue-router": "^4.3.0",
|
|
52
52
|
"zod": "^4.3.6",
|
|
53
53
|
"@commonpub/auth": "0.5.0",
|
|
54
|
-
"@commonpub/config": "0.8.0",
|
|
55
54
|
"@commonpub/docs": "0.6.0",
|
|
55
|
+
"@commonpub/config": "0.8.0",
|
|
56
56
|
"@commonpub/editor": "0.5.0",
|
|
57
|
-
"@commonpub/explainer": "0.6.
|
|
58
|
-
"@commonpub/
|
|
57
|
+
"@commonpub/explainer": "0.6.2",
|
|
58
|
+
"@commonpub/schema": "0.8.16",
|
|
59
59
|
"@commonpub/protocol": "0.9.6",
|
|
60
|
-
"@commonpub/
|
|
61
|
-
"@commonpub/
|
|
60
|
+
"@commonpub/server": "2.24.0",
|
|
61
|
+
"@commonpub/learning": "0.5.0",
|
|
62
62
|
"@commonpub/ui": "0.8.4"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
@@ -73,6 +73,7 @@ const selectedPage = computed<DocsPage | null>(() =>
|
|
|
73
73
|
|
|
74
74
|
// Page properties (right panel)
|
|
75
75
|
const pageSlug = ref('');
|
|
76
|
+
const pageStatus = ref<'draft' | 'published'>('draft');
|
|
76
77
|
const savingPage = ref(false);
|
|
77
78
|
const autoSaveTimer = ref<ReturnType<typeof setTimeout> | null>(null);
|
|
78
79
|
const autoSaveStatus = ref<'idle' | 'saving' | 'saved' | 'error'>('idle');
|
|
@@ -110,6 +111,7 @@ async function selectPage(pageId: string): Promise<void> {
|
|
|
110
111
|
|
|
111
112
|
// Load properties
|
|
112
113
|
pageSlug.value = page.slug ?? '';
|
|
114
|
+
pageStatus.value = ((page as Record<string, unknown>).status as 'draft' | 'published') || 'draft';
|
|
113
115
|
isDirty.value = false;
|
|
114
116
|
autoSaveStatus.value = 'idle';
|
|
115
117
|
|
|
@@ -146,6 +148,36 @@ async function saveCurrentPage(): Promise<void> {
|
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
// Autosave: debounce 5 seconds for docs (shorter than article 30s)
|
|
151
|
+
async function publishPage(): Promise<void> {
|
|
152
|
+
if (!selectedPageId.value) return;
|
|
153
|
+
try {
|
|
154
|
+
await $fetch(`/api/docs/${siteSlug.value}/pages/${selectedPageId.value}`, {
|
|
155
|
+
method: 'PUT',
|
|
156
|
+
body: { status: 'published' },
|
|
157
|
+
});
|
|
158
|
+
pageStatus.value = 'published';
|
|
159
|
+
await refreshPages();
|
|
160
|
+
toast('Page published', 'success');
|
|
161
|
+
} catch {
|
|
162
|
+
toast('Failed to publish', 'error');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function unpublishPage(): Promise<void> {
|
|
167
|
+
if (!selectedPageId.value) return;
|
|
168
|
+
try {
|
|
169
|
+
await $fetch(`/api/docs/${siteSlug.value}/pages/${selectedPageId.value}`, {
|
|
170
|
+
method: 'PUT',
|
|
171
|
+
body: { status: 'draft' },
|
|
172
|
+
});
|
|
173
|
+
pageStatus.value = 'draft';
|
|
174
|
+
await refreshPages();
|
|
175
|
+
toast('Page unpublished', 'success');
|
|
176
|
+
} catch {
|
|
177
|
+
toast('Failed to unpublish', 'error');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
149
181
|
function scheduleAutoSave(): void {
|
|
150
182
|
if (autoSaveTimer.value) clearTimeout(autoSaveTimer.value);
|
|
151
183
|
autoSaveTimer.value = setTimeout(() => {
|
|
@@ -499,22 +531,66 @@ async function createVersion(): Promise<void> {
|
|
|
499
531
|
</div>
|
|
500
532
|
</template>
|
|
501
533
|
|
|
502
|
-
<!-- RIGHT:
|
|
534
|
+
<!-- RIGHT: Blocks + Properties -->
|
|
503
535
|
<template #right>
|
|
504
|
-
<div v-if="selectedPage" class="cpub-docs-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
<
|
|
509
|
-
|
|
536
|
+
<div v-if="selectedPage" class="cpub-docs-right">
|
|
537
|
+
<!-- Block palette -->
|
|
538
|
+
<div class="cpub-docs-right-section">
|
|
539
|
+
<h3 class="cpub-docs-props-heading">Blocks</h3>
|
|
540
|
+
<div class="cpub-docs-block-list">
|
|
541
|
+
<template v-for="group in blockTypes" :key="group.name">
|
|
542
|
+
<button
|
|
543
|
+
v-for="block in group.blocks"
|
|
544
|
+
:key="block.type + (block.attrs?.variant || '')"
|
|
545
|
+
class="cpub-docs-block-btn"
|
|
546
|
+
@click="blockEditor.addBlock(block.type, block.attrs)"
|
|
547
|
+
>
|
|
548
|
+
<i :class="`fa-solid ${block.icon}`" class="cpub-docs-block-icon" />
|
|
549
|
+
<span>{{ block.label }}</span>
|
|
550
|
+
</button>
|
|
551
|
+
</template>
|
|
552
|
+
</div>
|
|
510
553
|
</div>
|
|
511
554
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
<
|
|
515
|
-
|
|
555
|
+
<!-- Page properties -->
|
|
556
|
+
<div class="cpub-docs-right-section">
|
|
557
|
+
<h3 class="cpub-docs-props-heading">Properties</h3>
|
|
558
|
+
|
|
559
|
+
<div class="cpub-docs-field">
|
|
560
|
+
<label class="cpub-docs-field-label">Slug</label>
|
|
561
|
+
<input v-model="pageSlug" class="cpub-docs-field-input" placeholder="page-slug" />
|
|
562
|
+
</div>
|
|
563
|
+
|
|
564
|
+
<div class="cpub-docs-field">
|
|
565
|
+
<label class="cpub-docs-field-label">Status</label>
|
|
566
|
+
<div class="cpub-docs-status-row">
|
|
567
|
+
<span class="cpub-docs-status-badge" :class="pageStatus === 'published' ? 'cpub-docs-status-published' : 'cpub-docs-status-draft'">
|
|
568
|
+
{{ pageStatus === 'published' ? 'Published' : 'Draft' }}
|
|
569
|
+
</span>
|
|
570
|
+
<button
|
|
571
|
+
v-if="pageStatus !== 'published'"
|
|
572
|
+
class="cpub-docs-publish-btn"
|
|
573
|
+
@click="publishPage"
|
|
574
|
+
>
|
|
575
|
+
<i class="fa-solid fa-globe" /> Publish
|
|
576
|
+
</button>
|
|
577
|
+
<button
|
|
578
|
+
v-else
|
|
579
|
+
class="cpub-docs-unpublish-btn"
|
|
580
|
+
@click="unpublishPage"
|
|
581
|
+
>
|
|
582
|
+
Unpublish
|
|
583
|
+
</button>
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
|
|
587
|
+
<div class="cpub-docs-field">
|
|
588
|
+
<label class="cpub-docs-field-label">Parent</label>
|
|
589
|
+
<div class="cpub-docs-field-value">
|
|
590
|
+
{{ selectedPage?.parentId ? pages.find(p => p.id === selectedPage!.parentId)?.title ?? 'Unknown' : 'Top level' }}
|
|
591
|
+
</div>
|
|
592
|
+
<span class="cpub-docs-field-hint">Drag pages in the tree to change hierarchy</span>
|
|
516
593
|
</div>
|
|
517
|
-
<span class="cpub-docs-field-hint">Drag pages in the tree to change hierarchy</span>
|
|
518
594
|
</div>
|
|
519
595
|
</div>
|
|
520
596
|
</template>
|
|
@@ -838,6 +914,117 @@ async function createVersion(): Promise<void> {
|
|
|
838
914
|
line-height: 1.3;
|
|
839
915
|
}
|
|
840
916
|
|
|
917
|
+
/* Right panel layout */
|
|
918
|
+
.cpub-docs-right {
|
|
919
|
+
display: flex;
|
|
920
|
+
flex-direction: column;
|
|
921
|
+
gap: 0;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.cpub-docs-right-section {
|
|
925
|
+
padding: 12px 0;
|
|
926
|
+
border-bottom: var(--border-width-default) solid var(--border2);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.cpub-docs-right-section:last-child {
|
|
930
|
+
border-bottom: none;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/* Block palette */
|
|
934
|
+
.cpub-docs-block-list {
|
|
935
|
+
display: flex;
|
|
936
|
+
flex-direction: column;
|
|
937
|
+
gap: 2px;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.cpub-docs-block-btn {
|
|
941
|
+
display: flex;
|
|
942
|
+
align-items: center;
|
|
943
|
+
gap: 8px;
|
|
944
|
+
padding: 5px 8px;
|
|
945
|
+
background: none;
|
|
946
|
+
border: var(--border-width-default) solid transparent;
|
|
947
|
+
color: var(--text-dim);
|
|
948
|
+
font-size: 11px;
|
|
949
|
+
cursor: pointer;
|
|
950
|
+
text-align: left;
|
|
951
|
+
width: 100%;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
.cpub-docs-block-btn:hover {
|
|
955
|
+
background: var(--surface2);
|
|
956
|
+
border-color: var(--border);
|
|
957
|
+
color: var(--text);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
.cpub-docs-block-icon {
|
|
961
|
+
width: 14px;
|
|
962
|
+
font-size: 10px;
|
|
963
|
+
color: var(--text-faint);
|
|
964
|
+
text-align: center;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/* Status badge + publish */
|
|
968
|
+
.cpub-docs-status-row {
|
|
969
|
+
display: flex;
|
|
970
|
+
align-items: center;
|
|
971
|
+
gap: 8px;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
.cpub-docs-status-badge {
|
|
975
|
+
font-family: var(--font-mono);
|
|
976
|
+
font-size: 9px;
|
|
977
|
+
font-weight: 700;
|
|
978
|
+
text-transform: uppercase;
|
|
979
|
+
letter-spacing: 0.06em;
|
|
980
|
+
padding: 2px 8px;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.cpub-docs-status-draft {
|
|
984
|
+
color: var(--yellow, #d4a017);
|
|
985
|
+
background: var(--yellow-bg, rgba(245, 158, 11, 0.08));
|
|
986
|
+
border: var(--border-width-default) solid var(--yellow-border, rgba(245, 158, 11, 0.25));
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
.cpub-docs-status-published {
|
|
990
|
+
color: var(--green, #2a9d5c);
|
|
991
|
+
background: var(--green-bg, rgba(34, 197, 94, 0.08));
|
|
992
|
+
border: var(--border-width-default) solid var(--green-border, rgba(34, 197, 94, 0.25));
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
.cpub-docs-publish-btn {
|
|
996
|
+
padding: 3px 10px;
|
|
997
|
+
background: var(--accent);
|
|
998
|
+
border: var(--border-width-default) solid var(--accent);
|
|
999
|
+
color: var(--color-text-inverse, #fff);
|
|
1000
|
+
font-family: var(--font-mono);
|
|
1001
|
+
font-size: 9px;
|
|
1002
|
+
font-weight: 700;
|
|
1003
|
+
cursor: pointer;
|
|
1004
|
+
display: flex;
|
|
1005
|
+
align-items: center;
|
|
1006
|
+
gap: 5px;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
.cpub-docs-publish-btn:hover {
|
|
1010
|
+
opacity: 0.85;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
.cpub-docs-unpublish-btn {
|
|
1014
|
+
padding: 3px 10px;
|
|
1015
|
+
background: none;
|
|
1016
|
+
border: var(--border-width-default) solid var(--border);
|
|
1017
|
+
color: var(--text-faint);
|
|
1018
|
+
font-family: var(--font-mono);
|
|
1019
|
+
font-size: 9px;
|
|
1020
|
+
cursor: pointer;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
.cpub-docs-unpublish-btn:hover {
|
|
1024
|
+
color: var(--yellow, #d4a017);
|
|
1025
|
+
border-color: var(--yellow, #d4a017);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
841
1028
|
.cpub-docs-field-value {
|
|
842
1029
|
font-size: 12px;
|
|
843
1030
|
color: var(--text-dim);
|