This commit is contained in:
1 parent
19d934065c
commit
609c6e18e2
4 files changed
+56
-136
No files matched your search
@@ -2,12 +2,12 @@
|
|||||||
import { resolve } from '$app/paths';
|
import { resolve } from '$app/paths';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import type { PageData, ActionData } from './$types';
|
import type { PageData, ActionData } from './$types';
|
||||||
import MarkdownRenderer from '$lib/components/MarkdownRenderer.svelte';
|
import ContentEditor from '$lib/components/admin/ContentEditor.svelte';
|
||||||
import MarkdownEditor from '$lib/components/admin/MarkdownEditor.svelte';
|
import { EditorOutline } from '$lib/editor/outline.svelte';
|
||||||
import TextInput from '$lib/components/admin/TextInput.svelte';
|
import TextInput from '$lib/components/admin/TextInput.svelte';
|
||||||
import Button from '$lib/components/admin/Button.svelte';
|
import Button from '$lib/components/admin/Button.svelte';
|
||||||
import Alert from '$lib/components/admin/Alert.svelte';
|
import Alert from '$lib/components/admin/Alert.svelte';
|
||||||
import Tabs from '$lib/components/admin/Tabs.svelte';
|
import EditorSidebarTabs from '$lib/components/admin/EditorSidebarTabs.svelte';
|
||||||
import ArticleAttachments from '$lib/components/admin/ArticleAttachments.svelte';
|
import ArticleAttachments from '$lib/components/admin/ArticleAttachments.svelte';
|
||||||
import { untrack } from 'svelte';
|
import { untrack } from 'svelte';
|
||||||
import { ArrowLeft } from 'lucide-svelte';
|
import { ArrowLeft } from 'lucide-svelte';
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
let content = $state(initialData.page.content);
|
let content = $state(initialData.page.content);
|
||||||
let mode = $state<'edit' | 'preview'>('edit');
|
let mode = $state<'edit' | 'preview'>('edit');
|
||||||
|
|
||||||
|
const outline = new EditorOutline();
|
||||||
let sidebarTab = $state('settings');
|
let sidebarTab = $state('settings');
|
||||||
let sessionUploads = $state<{ url: string; key: string; filename: string }[]>([]);
|
let sessionUploads = $state<{ url: string; key: string; filename: string }[]>([]);
|
||||||
</script>
|
</script>
|
||||||
@@ -76,30 +77,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-body">
|
<div class="editor-body">
|
||||||
{#if mode === 'edit'}
|
<ContentEditor
|
||||||
<MarkdownEditor
|
bind:value={content}
|
||||||
bind:value={content}
|
{mode}
|
||||||
onUpload={(img) => (sessionUploads = [...sessionUploads, img])}
|
{outline}
|
||||||
/>
|
onUpload={(img) => (sessionUploads = [...sessionUploads, img])}
|
||||||
{:else}
|
/>
|
||||||
<div class="preview-area">
|
|
||||||
<MarkdownRenderer {content} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-sidebar">
|
<div class="form-sidebar">
|
||||||
<Tabs
|
<EditorSidebarTabs {outline} bind:activeTab={sidebarTab} />
|
||||||
tabs={[
|
|
||||||
{ id: 'settings', label: '设置' },
|
|
||||||
{ id: 'media', label: '媒体附件' }
|
|
||||||
]}
|
|
||||||
bind:activeTab={sidebarTab}
|
|
||||||
fullWidth={true}
|
|
||||||
small={true}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 设置面板始终挂载(仅切换显隐),确保别名字段在提交时始终存在 -->
|
<!-- 设置面板始终挂载(仅切换显隐),确保别名字段在提交时始终存在 -->
|
||||||
<div class="sidebar-panel" class:is-hidden={sidebarTab !== 'settings'}>
|
<div class="sidebar-panel" class:is-hidden={sidebarTab !== 'settings'}>
|
||||||
@@ -183,23 +172,15 @@
|
|||||||
background: rgba(65, 155, 56, 0.1);
|
background: rgba(65, 155, 56, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-area {
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
||||||
background: rgba(0, 0, 0, 0.015);
|
|
||||||
min-height: 400px;
|
|
||||||
max-height: 600px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-grid {
|
.form-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 280px;
|
grid-template-columns: minmax(0, 1fr) 280px;
|
||||||
gap: 40px;
|
gap: 40px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-main {
|
.form-main {
|
||||||
|
min-width: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,8 +211,7 @@
|
|||||||
|
|
||||||
.form-sidebar {
|
.form-sidebar {
|
||||||
position: static;
|
position: static;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
import { resolve } from '$app/paths';
|
import { resolve } from '$app/paths';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import type { ActionData } from './$types';
|
import type { ActionData } from './$types';
|
||||||
import MarkdownRenderer from '$lib/components/MarkdownRenderer.svelte';
|
import ContentEditor from '$lib/components/admin/ContentEditor.svelte';
|
||||||
import MarkdownEditor from '$lib/components/admin/MarkdownEditor.svelte';
|
import { EditorOutline } from '$lib/editor/outline.svelte';
|
||||||
import TextInput from '$lib/components/admin/TextInput.svelte';
|
import TextInput from '$lib/components/admin/TextInput.svelte';
|
||||||
import Button from '$lib/components/admin/Button.svelte';
|
import Button from '$lib/components/admin/Button.svelte';
|
||||||
import Alert from '$lib/components/admin/Alert.svelte';
|
import Alert from '$lib/components/admin/Alert.svelte';
|
||||||
import Tabs from '$lib/components/admin/Tabs.svelte';
|
import EditorSidebarTabs from '$lib/components/admin/EditorSidebarTabs.svelte';
|
||||||
import ArticleAttachments from '$lib/components/admin/ArticleAttachments.svelte';
|
import ArticleAttachments from '$lib/components/admin/ArticleAttachments.svelte';
|
||||||
|
|
||||||
import { createSlugAutoHandler } from '$lib/utils/slugify';
|
import { createSlugAutoHandler } from '$lib/utils/slugify';
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
let isSlugUserModified = $state(false);
|
let isSlugUserModified = $state(false);
|
||||||
let isGenerating = $state(false);
|
let isGenerating = $state(false);
|
||||||
|
|
||||||
|
const outline = new EditorOutline();
|
||||||
let sidebarTab = $state('settings');
|
let sidebarTab = $state('settings');
|
||||||
let sessionUploads = $state<{ url: string; key: string; filename: string }[]>([]);
|
let sessionUploads = $state<{ url: string; key: string; filename: string }[]>([]);
|
||||||
|
|
||||||
@@ -92,30 +93,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-body">
|
<div class="editor-body">
|
||||||
{#if mode === 'edit'}
|
<ContentEditor
|
||||||
<MarkdownEditor
|
bind:value={content}
|
||||||
bind:value={content}
|
{mode}
|
||||||
onUpload={(img) => (sessionUploads = [...sessionUploads, img])}
|
{outline}
|
||||||
/>
|
onUpload={(img) => (sessionUploads = [...sessionUploads, img])}
|
||||||
{:else}
|
/>
|
||||||
<div class="preview-area">
|
|
||||||
<MarkdownRenderer {content} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-sidebar">
|
<div class="form-sidebar">
|
||||||
<Tabs
|
<EditorSidebarTabs {outline} bind:activeTab={sidebarTab} />
|
||||||
tabs={[
|
|
||||||
{ id: 'settings', label: '设置' },
|
|
||||||
{ id: 'media', label: '媒体附件' }
|
|
||||||
]}
|
|
||||||
bind:activeTab={sidebarTab}
|
|
||||||
fullWidth={true}
|
|
||||||
small={true}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 设置面板始终挂载(仅切换显隐),确保别名字段在提交时始终存在 -->
|
<!-- 设置面板始终挂载(仅切换显隐),确保别名字段在提交时始终存在 -->
|
||||||
<div class="sidebar-panel" class:is-hidden={sidebarTab !== 'settings'}>
|
<div class="sidebar-panel" class:is-hidden={sidebarTab !== 'settings'}>
|
||||||
@@ -210,23 +199,15 @@
|
|||||||
background: rgba(65, 155, 56, 0.1);
|
background: rgba(65, 155, 56, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-area {
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
||||||
background: rgba(0, 0, 0, 0.015);
|
|
||||||
min-height: 400px;
|
|
||||||
max-height: 600px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-grid {
|
.form-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 280px;
|
grid-template-columns: minmax(0, 1fr) 280px;
|
||||||
gap: 40px;
|
gap: 40px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-main {
|
.form-main {
|
||||||
|
min-width: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,8 +238,7 @@
|
|||||||
|
|
||||||
.form-sidebar {
|
.form-sidebar {
|
||||||
position: static;
|
position: static;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
import type { PageData, ActionData } from './$types';
|
import type { PageData, ActionData } from './$types';
|
||||||
import { deserialize } from '$app/forms';
|
import { deserialize } from '$app/forms';
|
||||||
import { Save, X } from 'lucide-svelte';
|
import { Save, X } from 'lucide-svelte';
|
||||||
import MarkdownRenderer from '$lib/components/MarkdownRenderer.svelte';
|
import ContentEditor from '$lib/components/admin/ContentEditor.svelte';
|
||||||
import MarkdownEditor from '$lib/components/admin/MarkdownEditor.svelte';
|
import { EditorOutline } from '$lib/editor/outline.svelte';
|
||||||
import FeaturedImagePicker from '$lib/components/admin/FeaturedImagePicker.svelte';
|
import FeaturedImagePicker from '$lib/components/admin/FeaturedImagePicker.svelte';
|
||||||
import SelectDropdown from '$lib/components/admin/SelectDropdown.svelte';
|
import SelectDropdown from '$lib/components/admin/SelectDropdown.svelte';
|
||||||
import TextInput from '$lib/components/admin/TextInput.svelte';
|
import TextInput from '$lib/components/admin/TextInput.svelte';
|
||||||
import Button from '$lib/components/admin/Button.svelte';
|
import Button from '$lib/components/admin/Button.svelte';
|
||||||
import Alert from '$lib/components/admin/Alert.svelte';
|
import Alert from '$lib/components/admin/Alert.svelte';
|
||||||
import Tabs from '$lib/components/admin/Tabs.svelte';
|
import EditorSidebarTabs from '$lib/components/admin/EditorSidebarTabs.svelte';
|
||||||
import ArticleAttachments from '$lib/components/admin/ArticleAttachments.svelte';
|
import ArticleAttachments from '$lib/components/admin/ArticleAttachments.svelte';
|
||||||
import { untrack } from 'svelte';
|
import { untrack } from 'svelte';
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
let tagsList = $state(initialData.tags || []);
|
let tagsList = $state(initialData.tags || []);
|
||||||
let seriesList = $state(initialData.series || []);
|
let seriesList = $state(initialData.series || []);
|
||||||
|
|
||||||
|
const outline = new EditorOutline();
|
||||||
let sidebarTab = $state('settings');
|
let sidebarTab = $state('settings');
|
||||||
let sessionUploads = $state<{ url: string; key: string; filename: string }[]>([]);
|
let sessionUploads = $state<{ url: string; key: string; filename: string }[]>([]);
|
||||||
|
|
||||||
@@ -166,30 +167,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-body">
|
<div class="editor-body">
|
||||||
{#if mode === 'edit'}
|
<ContentEditor
|
||||||
<MarkdownEditor
|
bind:value={content}
|
||||||
bind:value={content}
|
{mode}
|
||||||
onUpload={(img) => (sessionUploads = [...sessionUploads, img])}
|
{outline}
|
||||||
/>
|
onUpload={(img) => (sessionUploads = [...sessionUploads, img])}
|
||||||
{:else}
|
/>
|
||||||
<div class="preview-area">
|
|
||||||
<MarkdownRenderer {content} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-sidebar">
|
<div class="form-sidebar">
|
||||||
<Tabs
|
<EditorSidebarTabs {outline} bind:activeTab={sidebarTab} />
|
||||||
tabs={[
|
|
||||||
{ id: 'settings', label: '设置' },
|
|
||||||
{ id: 'media', label: '媒体附件' }
|
|
||||||
]}
|
|
||||||
bind:activeTab={sidebarTab}
|
|
||||||
fullWidth={true}
|
|
||||||
small={true}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 设置面板始终挂载(仅切换显隐),确保别名/分类/系列/标签等字段在提交时始终存在 -->
|
<!-- 设置面板始终挂载(仅切换显隐),确保别名/分类/系列/标签等字段在提交时始终存在 -->
|
||||||
<div class="sidebar-panel" class:is-hidden={sidebarTab !== 'settings'}>
|
<div class="sidebar-panel" class:is-hidden={sidebarTab !== 'settings'}>
|
||||||
@@ -378,23 +367,15 @@
|
|||||||
background: rgba(65, 155, 56, 0.1);
|
background: rgba(65, 155, 56, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-area {
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
||||||
background: rgba(0, 0, 0, 0.015);
|
|
||||||
min-height: 400px;
|
|
||||||
max-height: 600px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-grid {
|
.form-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 280px;
|
grid-template-columns: minmax(0, 1fr) 280px;
|
||||||
gap: 40px;
|
gap: 40px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-main {
|
.form-main {
|
||||||
|
min-width: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,8 +406,7 @@
|
|||||||
|
|
||||||
.form-sidebar {
|
.form-sidebar {
|
||||||
position: static;
|
position: static;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
import type { PageData, ActionData } from './$types';
|
import type { PageData, ActionData } from './$types';
|
||||||
import { deserialize } from '$app/forms';
|
import { deserialize } from '$app/forms';
|
||||||
import { ArrowLeft, X } from 'lucide-svelte';
|
import { ArrowLeft, X } from 'lucide-svelte';
|
||||||
import MarkdownRenderer from '$lib/components/MarkdownRenderer.svelte';
|
import ContentEditor from '$lib/components/admin/ContentEditor.svelte';
|
||||||
import MarkdownEditor from '$lib/components/admin/MarkdownEditor.svelte';
|
import { EditorOutline } from '$lib/editor/outline.svelte';
|
||||||
import FeaturedImagePicker from '$lib/components/admin/FeaturedImagePicker.svelte';
|
import FeaturedImagePicker from '$lib/components/admin/FeaturedImagePicker.svelte';
|
||||||
import SelectDropdown from '$lib/components/admin/SelectDropdown.svelte';
|
import SelectDropdown from '$lib/components/admin/SelectDropdown.svelte';
|
||||||
import TextInput from '$lib/components/admin/TextInput.svelte';
|
import TextInput from '$lib/components/admin/TextInput.svelte';
|
||||||
import Button from '$lib/components/admin/Button.svelte';
|
import Button from '$lib/components/admin/Button.svelte';
|
||||||
import Alert from '$lib/components/admin/Alert.svelte';
|
import Alert from '$lib/components/admin/Alert.svelte';
|
||||||
import Tabs from '$lib/components/admin/Tabs.svelte';
|
import EditorSidebarTabs from '$lib/components/admin/EditorSidebarTabs.svelte';
|
||||||
import ArticleAttachments from '$lib/components/admin/ArticleAttachments.svelte';
|
import ArticleAttachments from '$lib/components/admin/ArticleAttachments.svelte';
|
||||||
import { untrack } from 'svelte';
|
import { untrack } from 'svelte';
|
||||||
|
|
||||||
@@ -47,6 +47,7 @@
|
|||||||
setIsGenerating: (val) => (isGenerating = val)
|
setIsGenerating: (val) => (isGenerating = val)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const outline = new EditorOutline();
|
||||||
let sidebarTab = $state('settings');
|
let sidebarTab = $state('settings');
|
||||||
let sessionUploads = $state<{ url: string; key: string; filename: string }[]>([]);
|
let sessionUploads = $state<{ url: string; key: string; filename: string }[]>([]);
|
||||||
|
|
||||||
@@ -185,30 +186,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-body">
|
<div class="editor-body">
|
||||||
{#if mode === 'edit'}
|
<ContentEditor
|
||||||
<MarkdownEditor
|
bind:value={content}
|
||||||
bind:value={content}
|
{mode}
|
||||||
onUpload={(img) => (sessionUploads = [...sessionUploads, img])}
|
{outline}
|
||||||
/>
|
onUpload={(img) => (sessionUploads = [...sessionUploads, img])}
|
||||||
{:else}
|
/>
|
||||||
<div class="preview-area">
|
|
||||||
<MarkdownRenderer {content} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-sidebar">
|
<div class="form-sidebar">
|
||||||
<Tabs
|
<EditorSidebarTabs {outline} bind:activeTab={sidebarTab} />
|
||||||
tabs={[
|
|
||||||
{ id: 'settings', label: '设置' },
|
|
||||||
{ id: 'media', label: '媒体附件' }
|
|
||||||
]}
|
|
||||||
bind:activeTab={sidebarTab}
|
|
||||||
fullWidth={true}
|
|
||||||
small={true}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 设置面板始终挂载(仅切换显隐),确保别名/分类/系列/标签等字段在提交时始终存在 -->
|
<!-- 设置面板始终挂载(仅切换显隐),确保别名/分类/系列/标签等字段在提交时始终存在 -->
|
||||||
<div class="sidebar-panel" class:is-hidden={sidebarTab !== 'settings'}>
|
<div class="sidebar-panel" class:is-hidden={sidebarTab !== 'settings'}>
|
||||||
@@ -397,23 +386,15 @@
|
|||||||
background: rgba(65, 155, 56, 0.1);
|
background: rgba(65, 155, 56, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-area {
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
||||||
background: rgba(0, 0, 0, 0.015);
|
|
||||||
min-height: 400px;
|
|
||||||
max-height: 600px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-grid {
|
.form-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 280px;
|
grid-template-columns: minmax(0, 1fr) 280px;
|
||||||
gap: 40px;
|
gap: 40px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-main {
|
.form-main {
|
||||||
|
min-width: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,8 +425,7 @@
|
|||||||
|
|
||||||
.form-sidebar {
|
.form-sidebar {
|
||||||
position: static;
|
position: static;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user