fix: replace any types in frontend components
- use Leaflet types (L.Map, L.Marker, L.LeafletEvent) for map components - use Post and Project types from Prisma for form components - use JSONContent type for editor instances - use Snippet type for Svelte 5 render functions - use EditorView type for TipTap/ProseMirror views - use proper type guards for error handling - add editor interface types for save/clear methods
This commit is contained in:
parent
8ec4c582c1
commit
9c746d51c0
12 changed files with 50 additions and 42 deletions
|
|
@ -19,9 +19,9 @@
|
|||
}: Props = $props()
|
||||
|
||||
let mapContainer: HTMLDivElement
|
||||
let map: any
|
||||
let marker: any
|
||||
let leaflet: any
|
||||
let map: L.Map | null = null
|
||||
let marker: L.Marker | null = null
|
||||
let leaflet: typeof L | null = null
|
||||
|
||||
// Load Leaflet dynamically
|
||||
async function loadLeaflet() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte'
|
||||
|
||||
interface Props {
|
||||
left?: any
|
||||
right?: any
|
||||
left?: Snippet
|
||||
right?: Snippet
|
||||
}
|
||||
|
||||
let { left, right }: Props = $props()
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@
|
|||
let isSaving = $state(false)
|
||||
let validationErrors = $state<Record<string, string>>({})
|
||||
let showBulkAlbumModal = $state(false)
|
||||
let albumMedia = $state<any[]>([])
|
||||
let editorInstance = $state<any>()
|
||||
let albumMedia = $state<Array<{ media: Media; displayOrder: number }>>([])
|
||||
let editorInstance = $state<{ save: () => Promise<JSONContent>; clear: () => void } | undefined>()
|
||||
let activeTab = $state('metadata')
|
||||
let pendingMediaIds = $state<number[]>([]) // Photos to add after album creation
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
import { makeDraftKey, saveDraft, loadDraft, clearDraft, timeAgo } from '$lib/admin/draftStore'
|
||||
import { createAutoSaveStore } from '$lib/admin/autoSave.svelte'
|
||||
import AutoSaveStatus from './AutoSaveStatus.svelte'
|
||||
import type { JSONContent } from '@tiptap/core'
|
||||
import type { JSONContent, Editor as TipTapEditor } from '@tiptap/core'
|
||||
import type { Post } from '@prisma/client'
|
||||
|
||||
interface Props {
|
||||
postId?: number
|
||||
|
|
@ -43,7 +44,7 @@
|
|||
let tagInput = $state('')
|
||||
|
||||
// Ref to the editor component
|
||||
let editorRef: any
|
||||
let editorRef: { save: () => Promise<JSONContent> } | undefined
|
||||
|
||||
// Draft backup
|
||||
const draftKey = $derived(makeDraftKey('post', postId ?? 'new'))
|
||||
|
|
@ -80,8 +81,8 @@ let autoSave = mode === 'edit' && postId
|
|||
if (!response.ok) throw new Error('Failed to save')
|
||||
return await response.json()
|
||||
},
|
||||
onSaved: (saved: any, { prime }) => {
|
||||
updatedAt = saved.updatedAt
|
||||
onSaved: (saved: Post, { prime }) => {
|
||||
updatedAt = saved.updatedAt.toISOString()
|
||||
prime(buildPayload())
|
||||
if (draftKey) clearDraft(draftKey)
|
||||
}
|
||||
|
|
@ -144,7 +145,7 @@ $effect(() => {
|
|||
|
||||
// Show restore prompt if a draft exists
|
||||
$effect(() => {
|
||||
const draft = loadDraft<any>(draftKey)
|
||||
const draft = loadDraft<ReturnType<typeof buildPayload>>(draftKey)
|
||||
if (draft) {
|
||||
showDraftPrompt = true
|
||||
draftTimestamp = draft.ts
|
||||
|
|
@ -152,7 +153,7 @@ $effect(() => {
|
|||
})
|
||||
|
||||
function restoreDraft() {
|
||||
const draft = loadDraft<any>(draftKey)
|
||||
const draft = loadDraft<ReturnType<typeof buildPayload>>(draftKey)
|
||||
if (!draft) return
|
||||
const p = draft.payload
|
||||
title = p.title ?? title
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte'
|
||||
|
||||
interface Props {
|
||||
label: string
|
||||
name?: string
|
||||
type?: string
|
||||
value?: any
|
||||
value?: string | number
|
||||
placeholder?: string
|
||||
required?: boolean
|
||||
error?: string
|
||||
helpText?: string
|
||||
disabled?: boolean
|
||||
onchange?: (e: Event) => void
|
||||
children?: any
|
||||
children?: Snippet
|
||||
}
|
||||
|
||||
let {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
content: [{ type: 'paragraph' }]
|
||||
}
|
||||
let characterCount = 0
|
||||
let editorInstance: any
|
||||
let editorInstance: { save: () => Promise<JSONContent>; clear: () => void } | undefined
|
||||
|
||||
// Essay metadata
|
||||
let essayTitle = ''
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<script lang="ts">
|
||||
import GenericMetadataPopover, { type MetadataConfig } from './GenericMetadataPopover.svelte'
|
||||
import type { Post } from '@prisma/client'
|
||||
|
||||
type Props = {
|
||||
post: any
|
||||
post: Post
|
||||
postType: 'post' | 'essay'
|
||||
slug: string
|
||||
tags: string[]
|
||||
|
|
@ -12,7 +13,7 @@
|
|||
onRemoveTag: (tag: string) => void
|
||||
onDelete: () => void
|
||||
onClose?: () => void
|
||||
onFieldUpdate?: (key: string, value: any) => void
|
||||
onFieldUpdate?: (key: string, value: unknown) => void
|
||||
}
|
||||
|
||||
let {
|
||||
|
|
@ -29,11 +30,11 @@
|
|||
onFieldUpdate
|
||||
}: Props = $props()
|
||||
|
||||
function handleFieldUpdate(key: string, value: any) {
|
||||
if (key === 'slug') {
|
||||
function handleFieldUpdate(key: string, value: unknown) {
|
||||
if (key === 'slug' && typeof value === 'string') {
|
||||
slug = value
|
||||
onFieldUpdate?.(key, value)
|
||||
} else if (key === 'tagInput') {
|
||||
} else if (key === 'tagInput' && typeof value === 'string') {
|
||||
tagInput = value
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
import { useFormGuards } from '$lib/admin/useFormGuards.svelte'
|
||||
import { makeDraftKey, saveDraft, clearDraft } from '$lib/admin/draftStore'
|
||||
import type { ProjectFormData } from '$lib/types/project'
|
||||
import type { JSONContent } from '@tiptap/core'
|
||||
|
||||
interface Props {
|
||||
project?: Project | null
|
||||
|
|
@ -37,7 +38,7 @@
|
|||
let successMessage = $state<string | null>(null)
|
||||
|
||||
// Ref to the editor component
|
||||
let editorRef: any
|
||||
let editorRef: { save: () => Promise<JSONContent> } | undefined
|
||||
|
||||
// Draft key for autosave fallback
|
||||
const draftKey = $derived(mode === 'edit' && project ? makeDraftKey('project', project.id) : null)
|
||||
|
|
@ -50,7 +51,7 @@
|
|||
save: async (payload, { signal }) => {
|
||||
return await api.put(`/api/projects/${project?.id}`, payload, { signal })
|
||||
},
|
||||
onSaved: (savedProject: any, { prime }) => {
|
||||
onSaved: (savedProject: Project, { prime }) => {
|
||||
project = savedProject
|
||||
formStore.populateFromProject(savedProject)
|
||||
prime(formStore.buildPayload())
|
||||
|
|
@ -112,7 +113,7 @@
|
|||
}
|
||||
})
|
||||
|
||||
function handleEditorChange(content: any) {
|
||||
function handleEditorChange(content: JSONContent) {
|
||||
formStore.setField('caseStudyContent', content)
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +159,7 @@
|
|||
}
|
||||
} catch (err) {
|
||||
toast.dismiss(loadingToastId)
|
||||
if ((err as any)?.status === 409) {
|
||||
if (err && typeof err === 'object' && 'status' in err && (err as { status: number }).status === 409) {
|
||||
toast.error('This project has changed in another tab. Please reload.')
|
||||
} else {
|
||||
toast.error(`Failed to ${mode === 'edit' ? 'save' : 'create'} project`)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Editor } from '@tiptap/core'
|
||||
import type { Editor, EditorView } from '@tiptap/core'
|
||||
import type { ComposerMediaHandler } from './ComposerMediaHandler.svelte'
|
||||
import { focusEditor } from '$lib/components/edra/utils'
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ export interface UseComposerEventsOptions {
|
|||
|
||||
export function useComposerEvents(options: UseComposerEventsOptions) {
|
||||
// Handle paste events
|
||||
function handlePaste(view: any, event: ClipboardEvent): boolean {
|
||||
function handlePaste(view: EditorView, event: ClipboardEvent): boolean {
|
||||
const clipboardData = event.clipboardData
|
||||
if (!clipboardData) return false
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ export function useComposerEvents(options: UseComposerEventsOptions) {
|
|||
event.preventDefault()
|
||||
|
||||
// Use editor commands to insert HTML content
|
||||
const editorInstance = (view as any).editor
|
||||
const editorInstance = options.editor
|
||||
if (editorInstance) {
|
||||
editorInstance
|
||||
.chain()
|
||||
|
|
@ -66,7 +66,7 @@ export function useComposerEvents(options: UseComposerEventsOptions) {
|
|||
}
|
||||
|
||||
// Handle drag and drop for images
|
||||
function handleDrop(view: any, event: DragEvent): boolean {
|
||||
function handleDrop(view: EditorView, event: DragEvent): boolean {
|
||||
if (!options.features.imageUpload || !options.mediaHandler) return false
|
||||
|
||||
const files = event.dataTransfer?.files
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@
|
|||
}
|
||||
|
||||
// Block manipulation functions
|
||||
function convertBlockType(type: string, attrs?: any) {
|
||||
function convertBlockType(type: string, attrs?: Record<string, unknown>) {
|
||||
console.log('convertBlockType called:', type, attrs)
|
||||
// Use menuNode which was captured when menu was opened
|
||||
const nodeToConvert = menuNode || currentNode
|
||||
|
|
@ -486,10 +486,11 @@
|
|||
// Find the existing drag handle created by the plugin and add click listener
|
||||
const checkForDragHandle = setInterval(() => {
|
||||
const existingDragHandle = document.querySelector('.drag-handle')
|
||||
if (existingDragHandle && !(existingDragHandle as any).__menuListener) {
|
||||
const element = existingDragHandle as HTMLElement & { __menuListener?: boolean }
|
||||
if (existingDragHandle && !element.__menuListener) {
|
||||
console.log('Found drag handle, adding click listener')
|
||||
existingDragHandle.addEventListener('click', handleMenuClick)
|
||||
;(existingDragHandle as any).__menuListener = true
|
||||
element.__menuListener = true
|
||||
|
||||
// Update our reference to use the existing drag handle
|
||||
dragHandleContainer = existingDragHandle as HTMLElement
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
let { node, updateAttributes }: Props = $props()
|
||||
|
||||
let mapContainer: HTMLDivElement
|
||||
let map: any
|
||||
let marker: any
|
||||
let leaflet: any
|
||||
let map: L.Map | null = null
|
||||
let marker: L.Marker | null = null
|
||||
let leaflet: typeof L | null = null
|
||||
let isEditing = $state(false)
|
||||
|
||||
// Extract attributes
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@
|
|||
// Map picker state
|
||||
let showMapPicker = $state(false)
|
||||
let mapContainer: HTMLDivElement
|
||||
let pickerMap: any
|
||||
let pickerMarker: any
|
||||
let leaflet: any
|
||||
let pickerMap: L.Map | null = null
|
||||
let pickerMarker: L.Marker | null = null
|
||||
let leaflet: typeof L | null = null
|
||||
|
||||
// Load Leaflet for map picker
|
||||
async function loadLeaflet() {
|
||||
|
|
@ -77,15 +77,15 @@
|
|||
.addTo(pickerMap)
|
||||
|
||||
// Update coordinates on marker drag
|
||||
pickerMarker.on('dragend', (e: any) => {
|
||||
const position = e.target.getLatLng()
|
||||
pickerMarker.on('dragend', (e: L.LeafletEvent) => {
|
||||
const position = (e.target as L.Marker).getLatLng()
|
||||
latitude = position.lat.toFixed(6)
|
||||
longitude = position.lng.toFixed(6)
|
||||
})
|
||||
|
||||
// Update marker on map click
|
||||
pickerMap.on('click', (e: any) => {
|
||||
pickerMarker.setLatLng(e.latlng)
|
||||
pickerMap.on('click', (e: L.LeafletMouseEvent) => {
|
||||
pickerMarker!.setLatLng(e.latlng)
|
||||
latitude = e.latlng.lat.toFixed(6)
|
||||
longitude = e.latlng.lng.toFixed(6)
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue