Add dropdown to change object publish state and fix z-index
This commit is contained in:
parent
f124fd1e69
commit
9ba787cd8b
15 changed files with 180 additions and 145 deletions
|
|
@ -131,7 +131,7 @@
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
background: rgba(0, 0, 0, 0.9);
|
background: rgba(0, 0, 0, 0.9);
|
||||||
z-index: 1000;
|
z-index: 1400;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 1000;
|
z-index: 1400;
|
||||||
padding: $unit-2x;
|
padding: $unit-2x;
|
||||||
|
|
||||||
@include breakpoint('phone') {
|
@include breakpoint('phone') {
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
z-index: 1000;
|
z-index: 1050;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
animation: slideDown 0.2s ease;
|
animation: slideDown 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
z-index: 10;
|
z-index: 1050;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
z-index: 1000;
|
z-index: 1050;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,6 @@
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
z-index: 10;
|
z-index: 1050;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@
|
||||||
popoverElement.style.position = 'fixed'
|
popoverElement.style.position = 'fixed'
|
||||||
popoverElement.style.top = `${top}px`
|
popoverElement.style.top = `${top}px`
|
||||||
popoverElement.style.left = `${left}px`
|
popoverElement.style.left = `${left}px`
|
||||||
popoverElement.style.zIndex = '1000'
|
popoverElement.style.zIndex = '1200'
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFieldUpdate(key: string, value: any) {
|
function handleFieldUpdate(key: string, value: any) {
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@
|
||||||
popoverElement.style.position = 'fixed'
|
popoverElement.style.position = 'fixed'
|
||||||
popoverElement.style.top = `${top}px`
|
popoverElement.style.top = `${top}px`
|
||||||
popoverElement.style.left = `${left}px`
|
popoverElement.style.left = `${left}px`
|
||||||
popoverElement.style.zIndex = '1000'
|
popoverElement.style.zIndex = '1200'
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 1000;
|
z-index: 1400;
|
||||||
padding: $unit-2x;
|
padding: $unit-2x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@
|
||||||
border-radius: $unit-2x;
|
border-radius: $unit-2x;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
min-width: 140px;
|
min-width: 140px;
|
||||||
z-index: 100;
|
z-index: 1050;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
||||||
|
|
@ -220,28 +220,26 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
{#if !isLoading}
|
{#if !isLoading}
|
||||||
{#if formData.status === 'published'}
|
<StatusDropdown
|
||||||
<Button variant="primary" buttonSize="large" onclick={handleSave} disabled={isSaving}>
|
currentStatus={formData.status}
|
||||||
{isSaving ? 'Saving...' : 'Save'}
|
onStatusChange={handleStatusChange}
|
||||||
</Button>
|
disabled={isSaving}
|
||||||
{:else}
|
isLoading={isSaving}
|
||||||
<StatusDropdown
|
primaryAction={
|
||||||
currentStatus={formData.status}
|
formData.status === 'published'
|
||||||
onStatusChange={handleStatusChange}
|
? { label: 'Save', status: 'published' }
|
||||||
disabled={isSaving}
|
: { label: 'Publish', status: 'published' }
|
||||||
isLoading={isSaving}
|
}
|
||||||
primaryAction={{ label: 'Publish', status: 'published' }}
|
dropdownActions={[
|
||||||
dropdownActions={[
|
{ label: 'Save as Draft', status: 'draft', show: formData.status !== 'draft' },
|
||||||
{ label: 'Save as Draft', status: 'draft' },
|
{ label: 'List Only', status: 'list-only', show: formData.status !== 'list-only' },
|
||||||
{ label: 'List Only', status: 'list-only', show: formData.status !== 'list-only' },
|
{
|
||||||
{
|
label: 'Password Protected',
|
||||||
label: 'Password Protected',
|
status: 'password-protected',
|
||||||
status: 'password-protected',
|
show: formData.status !== 'password-protected'
|
||||||
show: formData.status !== 'password-protected'
|
}
|
||||||
}
|
]}
|
||||||
]}
|
/>
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,11 @@ export async function uploadFile(
|
||||||
customOptions?: any
|
customOptions?: any
|
||||||
): Promise<UploadResult> {
|
): Promise<UploadResult> {
|
||||||
try {
|
try {
|
||||||
|
// TEMPORARY: Force Cloudinary usage for testing
|
||||||
|
const FORCE_CLOUDINARY_IN_DEV = true; // Toggle this to test
|
||||||
|
|
||||||
// Use local storage in development or when Cloudinary is not configured
|
// Use local storage in development or when Cloudinary is not configured
|
||||||
if (dev || !isCloudinaryConfigured()) {
|
if ((dev && !FORCE_CLOUDINARY_IN_DEV) || !isCloudinaryConfigured()) {
|
||||||
logger.info('Using local storage for file upload')
|
logger.info('Using local storage for file upload')
|
||||||
const localResult = await uploadFileLocally(file, type)
|
const localResult = await uploadFileLocally(file, type)
|
||||||
|
|
||||||
|
|
@ -123,14 +126,13 @@ export async function uploadFile(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log upload attempt for debugging
|
// Log upload attempt for debugging
|
||||||
if (isSvg) {
|
logger.info('Attempting file upload:', {
|
||||||
logger.info('Attempting SVG upload with options:', {
|
filename: file.name,
|
||||||
filename: file.name,
|
mimeType: file.type,
|
||||||
mimeType: file.type,
|
size: file.size,
|
||||||
size: file.size,
|
isSvg,
|
||||||
uploadOptions
|
uploadOptions
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// Upload to Cloudinary
|
// Upload to Cloudinary
|
||||||
const result = await new Promise<UploadApiResponse>((resolve, reject) => {
|
const result = await new Promise<UploadApiResponse>((resolve, reject) => {
|
||||||
|
|
@ -168,6 +170,17 @@ export async function uploadFile(
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Cloudinary upload failed', error as Error)
|
logger.error('Cloudinary upload failed', error as Error)
|
||||||
logger.mediaUpload(file.name, file.size, file.type, false)
|
logger.mediaUpload(file.name, file.size, file.type, false)
|
||||||
|
|
||||||
|
// Enhanced error logging
|
||||||
|
if (error instanceof Error) {
|
||||||
|
logger.error('Upload error details:', {
|
||||||
|
filename: file.name,
|
||||||
|
mimeType: file.type,
|
||||||
|
size: file.size,
|
||||||
|
errorMessage: error.message,
|
||||||
|
errorStack: error.stack
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
import MediaLibraryModal from '$lib/components/admin/MediaLibraryModal.svelte'
|
import MediaLibraryModal from '$lib/components/admin/MediaLibraryModal.svelte'
|
||||||
import MediaDetailsModal from '$lib/components/admin/MediaDetailsModal.svelte'
|
import MediaDetailsModal from '$lib/components/admin/MediaDetailsModal.svelte'
|
||||||
import GalleryUploader from '$lib/components/admin/GalleryUploader.svelte'
|
import GalleryUploader from '$lib/components/admin/GalleryUploader.svelte'
|
||||||
import SaveActionsGroup from '$lib/components/admin/SaveActionsGroup.svelte'
|
import StatusDropdown from '$lib/components/admin/StatusDropdown.svelte'
|
||||||
import AlbumMetadataPopover from '$lib/components/admin/AlbumMetadataPopover.svelte'
|
import AlbumMetadataPopover from '$lib/components/admin/AlbumMetadataPopover.svelte'
|
||||||
|
|
||||||
// Form state
|
// Form state
|
||||||
|
|
@ -93,7 +93,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSave(publishStatus?: 'draft' | 'published') {
|
async function handleSave(newStatus?: string) {
|
||||||
if (!title.trim()) {
|
if (!title.trim()) {
|
||||||
error = 'Title is required'
|
error = 'Title is required'
|
||||||
return
|
return
|
||||||
|
|
@ -122,7 +122,7 @@
|
||||||
location: location.trim() || null,
|
location: location.trim() || null,
|
||||||
isPhotography,
|
isPhotography,
|
||||||
showInUniverse,
|
showInUniverse,
|
||||||
status: publishStatus || status
|
status: newStatus || status
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(`/api/albums/${album.id}`, {
|
const response = await fetch(`/api/albums/${album.id}`, {
|
||||||
|
|
@ -142,8 +142,8 @@
|
||||||
const updatedAlbum = await response.json()
|
const updatedAlbum = await response.json()
|
||||||
album = updatedAlbum
|
album = updatedAlbum
|
||||||
|
|
||||||
if (publishStatus) {
|
if (newStatus) {
|
||||||
status = publishStatus
|
status = newStatus
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err instanceof Error ? err.message : 'Failed to update album'
|
error = err instanceof Error ? err.message : 'Failed to update album'
|
||||||
|
|
@ -591,12 +591,19 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<SaveActionsGroup
|
<StatusDropdown
|
||||||
{status}
|
currentStatus={status}
|
||||||
onSave={handleSave}
|
onStatusChange={handleSave}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
isLoading={isSaving}
|
isLoading={isSaving}
|
||||||
{canSave}
|
primaryAction={
|
||||||
|
status === 'published'
|
||||||
|
? { label: 'Save', status: 'published' }
|
||||||
|
: { label: 'Publish', status: 'published' }
|
||||||
|
}
|
||||||
|
dropdownActions={[
|
||||||
|
{ label: 'Save as Draft', status: 'draft', show: status !== 'draft' }
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
import PostMetadataPopover from '$lib/components/admin/PostMetadataPopover.svelte'
|
import PostMetadataPopover from '$lib/components/admin/PostMetadataPopover.svelte'
|
||||||
import DeleteConfirmationModal from '$lib/components/admin/DeleteConfirmationModal.svelte'
|
import DeleteConfirmationModal from '$lib/components/admin/DeleteConfirmationModal.svelte'
|
||||||
import Button from '$lib/components/admin/Button.svelte'
|
import Button from '$lib/components/admin/Button.svelte'
|
||||||
import SaveActionsGroup from '$lib/components/admin/SaveActionsGroup.svelte'
|
import StatusDropdown from '$lib/components/admin/StatusDropdown.svelte'
|
||||||
import type { JSONContent } from '@tiptap/core'
|
import type { JSONContent } from '@tiptap/core'
|
||||||
|
|
||||||
let post = $state<any>(null)
|
let post = $state<any>(null)
|
||||||
|
|
@ -48,49 +48,55 @@
|
||||||
type: 'paragraph',
|
type: 'paragraph',
|
||||||
content: block.content ? [{ type: 'text', text: block.content }] : []
|
content: block.content ? [{ type: 'text', text: block.content }] : []
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'heading':
|
case 'heading':
|
||||||
return {
|
return {
|
||||||
type: 'heading',
|
type: 'heading',
|
||||||
attrs: { level: block.level || 1 },
|
attrs: { level: block.level || 1 },
|
||||||
content: block.content ? [{ type: 'text', text: block.content }] : []
|
content: block.content ? [{ type: 'text', text: block.content }] : []
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'bulletList':
|
case 'bulletList':
|
||||||
case 'ul':
|
case 'ul':
|
||||||
return {
|
return {
|
||||||
type: 'bulletList',
|
type: 'bulletList',
|
||||||
content: (block.content || []).map((item: any) => ({
|
content: (block.content || []).map((item: any) => ({
|
||||||
type: 'listItem',
|
type: 'listItem',
|
||||||
content: [{
|
content: [
|
||||||
type: 'paragraph',
|
{
|
||||||
content: [{ type: 'text', text: item.content || item }]
|
type: 'paragraph',
|
||||||
}]
|
content: [{ type: 'text', text: item.content || item }]
|
||||||
|
}
|
||||||
|
]
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'orderedList':
|
case 'orderedList':
|
||||||
case 'ol':
|
case 'ol':
|
||||||
return {
|
return {
|
||||||
type: 'orderedList',
|
type: 'orderedList',
|
||||||
content: (block.content || []).map((item: any) => ({
|
content: (block.content || []).map((item: any) => ({
|
||||||
type: 'listItem',
|
type: 'listItem',
|
||||||
content: [{
|
content: [
|
||||||
type: 'paragraph',
|
{
|
||||||
content: [{ type: 'text', text: item.content || item }]
|
type: 'paragraph',
|
||||||
}]
|
content: [{ type: 'text', text: item.content || item }]
|
||||||
|
}
|
||||||
|
]
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'blockquote':
|
case 'blockquote':
|
||||||
return {
|
return {
|
||||||
type: 'blockquote',
|
type: 'blockquote',
|
||||||
content: [{
|
content: [
|
||||||
type: 'paragraph',
|
{
|
||||||
content: [{ type: 'text', text: block.content || '' }]
|
type: 'paragraph',
|
||||||
}]
|
content: [{ type: 'text', text: block.content || '' }]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'codeBlock':
|
case 'codeBlock':
|
||||||
case 'code':
|
case 'code':
|
||||||
return {
|
return {
|
||||||
|
|
@ -98,7 +104,7 @@
|
||||||
attrs: { language: block.language || '' },
|
attrs: { language: block.language || '' },
|
||||||
content: [{ type: 'text', text: block.content || '' }]
|
content: [{ type: 'text', text: block.content || '' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'image':
|
case 'image':
|
||||||
return {
|
return {
|
||||||
type: 'image',
|
type: 'image',
|
||||||
|
|
@ -108,11 +114,11 @@
|
||||||
title: block.caption || ''
|
title: block.caption || ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'hr':
|
case 'hr':
|
||||||
case 'horizontalRule':
|
case 'horizontalRule':
|
||||||
return { type: 'horizontalRule' }
|
return { type: 'horizontalRule' }
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Default to paragraph for unknown types
|
// Default to paragraph for unknown types
|
||||||
return {
|
return {
|
||||||
|
|
@ -134,66 +140,74 @@
|
||||||
return { blocks: [] }
|
return { blocks: [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
const blocks = tiptapContent.content.map((node: any) => {
|
const blocks = tiptapContent.content
|
||||||
switch (node.type) {
|
.map((node: any) => {
|
||||||
case 'paragraph':
|
switch (node.type) {
|
||||||
const text = extractTextFromNode(node)
|
case 'paragraph':
|
||||||
return text ? { type: 'paragraph', content: text } : null
|
const text = extractTextFromNode(node)
|
||||||
|
return text ? { type: 'paragraph', content: text } : null
|
||||||
case 'heading':
|
|
||||||
return {
|
case 'heading':
|
||||||
type: 'heading',
|
return {
|
||||||
level: node.attrs?.level || 1,
|
type: 'heading',
|
||||||
content: extractTextFromNode(node)
|
level: node.attrs?.level || 1,
|
||||||
}
|
content: extractTextFromNode(node)
|
||||||
|
}
|
||||||
case 'bulletList':
|
|
||||||
return {
|
case 'bulletList':
|
||||||
type: 'bulletList',
|
return {
|
||||||
content: node.content?.map((item: any) => {
|
type: 'bulletList',
|
||||||
const itemText = extractTextFromNode(item.content?.[0])
|
content:
|
||||||
return itemText
|
node.content
|
||||||
}).filter(Boolean) || []
|
?.map((item: any) => {
|
||||||
}
|
const itemText = extractTextFromNode(item.content?.[0])
|
||||||
|
return itemText
|
||||||
case 'orderedList':
|
})
|
||||||
return {
|
.filter(Boolean) || []
|
||||||
type: 'orderedList',
|
}
|
||||||
content: node.content?.map((item: any) => {
|
|
||||||
const itemText = extractTextFromNode(item.content?.[0])
|
case 'orderedList':
|
||||||
return itemText
|
return {
|
||||||
}).filter(Boolean) || []
|
type: 'orderedList',
|
||||||
}
|
content:
|
||||||
|
node.content
|
||||||
case 'blockquote':
|
?.map((item: any) => {
|
||||||
return {
|
const itemText = extractTextFromNode(item.content?.[0])
|
||||||
type: 'blockquote',
|
return itemText
|
||||||
content: extractTextFromNode(node.content?.[0])
|
})
|
||||||
}
|
.filter(Boolean) || []
|
||||||
|
}
|
||||||
case 'codeBlock':
|
|
||||||
return {
|
case 'blockquote':
|
||||||
type: 'codeBlock',
|
return {
|
||||||
language: node.attrs?.language || '',
|
type: 'blockquote',
|
||||||
content: node.content?.[0]?.text || ''
|
content: extractTextFromNode(node.content?.[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'image':
|
case 'codeBlock':
|
||||||
return {
|
return {
|
||||||
type: 'image',
|
type: 'codeBlock',
|
||||||
src: node.attrs?.src || '',
|
language: node.attrs?.language || '',
|
||||||
alt: node.attrs?.alt || '',
|
content: node.content?.[0]?.text || ''
|
||||||
caption: node.attrs?.title || ''
|
}
|
||||||
}
|
|
||||||
|
case 'image':
|
||||||
case 'horizontalRule':
|
return {
|
||||||
return { type: 'hr' }
|
type: 'image',
|
||||||
|
src: node.attrs?.src || '',
|
||||||
default:
|
alt: node.attrs?.alt || '',
|
||||||
// Skip unknown types
|
caption: node.attrs?.title || ''
|
||||||
return null
|
}
|
||||||
}
|
|
||||||
}).filter(Boolean)
|
case 'horizontalRule':
|
||||||
|
return { type: 'hr' }
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Skip unknown types
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
|
||||||
return { blocks }
|
return { blocks }
|
||||||
}
|
}
|
||||||
|
|
@ -244,7 +258,7 @@
|
||||||
status = post.status || 'draft'
|
status = post.status || 'draft'
|
||||||
slug = post.slug || ''
|
slug = post.slug || ''
|
||||||
excerpt = post.excerpt || ''
|
excerpt = post.excerpt || ''
|
||||||
|
|
||||||
// Convert blocks format to Tiptap format if needed
|
// Convert blocks format to Tiptap format if needed
|
||||||
if (post.content && post.content.blocks) {
|
if (post.content && post.content.blocks) {
|
||||||
content = convertBlocksToTiptap(post.content)
|
content = convertBlocksToTiptap(post.content)
|
||||||
|
|
@ -253,7 +267,7 @@
|
||||||
} else {
|
} else {
|
||||||
content = { type: 'doc', content: [] }
|
content = { type: 'doc', content: [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = post.tags || []
|
tags = post.tags || []
|
||||||
} else {
|
} else {
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
|
|
@ -283,7 +297,7 @@
|
||||||
tags = tags.filter((t) => t !== tag)
|
tags = tags.filter((t) => t !== tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSave(publishStatus?: 'draft' | 'published') {
|
async function handleSave(newStatus?: string) {
|
||||||
const auth = localStorage.getItem('admin_auth')
|
const auth = localStorage.getItem('admin_auth')
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
goto('/admin/login')
|
goto('/admin/login')
|
||||||
|
|
@ -291,18 +305,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
saving = true
|
saving = true
|
||||||
|
|
||||||
// Convert content to blocks format if it's in Tiptap format
|
// Convert content to blocks format if it's in Tiptap format
|
||||||
let saveContent = content
|
let saveContent = content
|
||||||
if (config?.showContent && content && content.type === 'doc') {
|
if (config?.showContent && content && content.type === 'doc') {
|
||||||
saveContent = convertTiptapToBlocks(content)
|
saveContent = convertTiptapToBlocks(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
const postData = {
|
const postData = {
|
||||||
title: config?.showTitle ? title : null,
|
title: config?.showTitle ? title : null,
|
||||||
slug,
|
slug,
|
||||||
type: postType,
|
type: postType,
|
||||||
status: publishStatus || status,
|
status: newStatus || status,
|
||||||
content: config?.showContent ? saveContent : null,
|
content: config?.showContent ? saveContent : null,
|
||||||
excerpt: postType === 'essay' ? excerpt : undefined,
|
excerpt: postType === 'essay' ? excerpt : undefined,
|
||||||
link_url: undefined,
|
link_url: undefined,
|
||||||
|
|
@ -322,8 +336,8 @@
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
post = await response.json()
|
post = await response.json()
|
||||||
if (publishStatus) {
|
if (newStatus) {
|
||||||
status = publishStatus
|
status = newStatus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -431,12 +445,15 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<SaveActionsGroup
|
<StatusDropdown
|
||||||
{status}
|
currentStatus={status}
|
||||||
onSave={handleSave}
|
onStatusChange={handleSave}
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
isLoading={saving}
|
isLoading={saving}
|
||||||
canSave={true}
|
primaryAction={status === 'published'
|
||||||
|
? { label: 'Save', status: 'published' }
|
||||||
|
: { label: 'Publish', status: 'published' }}
|
||||||
|
dropdownActions={[{ label: 'Save as Draft', status: 'draft', show: status !== 'draft' }]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
@ -591,7 +608,7 @@
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
z-index: 100;
|
z-index: 1050;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
z-index: 100;
|
z-index: 1050;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue