11import { createApp } from 'vue'
2- import type { Storage } from 'unstorage'
32import type { ParsedContent } from '@nuxt/content/dist/runtime/types'
4- import { createDefu } from 'defu'
53import type { RouteLocationNormalized } from 'vue-router'
64import type { AppConfig } from 'nuxt/schema'
75import ContentPreviewMode from '../components/ContentPreviewMode.vue'
8- import { createSingleton , deepAssign , deepDelete , mergeDraft , StudioConfigFiles } from '../utils'
6+ import { createSingleton , deepAssign , deepDelete , defu , mergeDraft , StudioConfigFiles } from '../utils'
97import type { PreviewFile , PreviewResponse , FileChangeMessagePayload } from '../types'
8+ import { useContentStorage } from './useContentStorage'
109import { callWithNuxt } from '#app'
11- import { useAppConfig , useNuxtApp , useRuntimeConfig , useState , useContentState , queryContent , ref , toRaw , useRoute , useRouter } from '#imports'
10+ import { useAppConfig , useNuxtApp , useRuntimeConfig , useContentState , ref , toRaw , useRoute , useRouter } from '#imports'
1211
1312const useDefaultAppConfig = createSingleton ( ( ) => JSON . parse ( JSON . stringify ( ( useAppConfig ( ) ) ) ) )
1413
15- const defu = createDefu ( ( obj , key , value ) => {
16- if ( Array . isArray ( obj [ key ] ) && Array . isArray ( value ) ) {
17- obj [ key ] = value
18- return true
19- }
20- } )
21-
2214let dbFiles : PreviewFile [ ] = [ ]
2315
2416export const useStudio = ( ) => {
2517 const nuxtApp = useNuxtApp ( )
18+ const { storage, findContentItem, updateContentItem, removeContentItem, removeAllContentItems, setPreviewMetaItems } = useContentStorage ( )
2619 const { studio : studioConfig , content : contentConfig } = useRuntimeConfig ( ) . public
27- const contentPathMap = { } as Record < string , ParsedContent >
2820 const apiURL = window . sessionStorage . getItem ( 'previewAPI' ) || studioConfig ?. apiURL
2921
3022 // App config (required)
3123 const initialAppConfig = useDefaultAppConfig ( )
32- const storage = useState < Storage | null > ( 'studio-client-db' , ( ) => null )
33-
34- if ( ! storage . value ) {
35- nuxtApp . hook ( 'content:storage' , ( _storage : Storage ) => {
36- storage . value = _storage
37- } )
3824
39- // Call `queryContent` to trigger `content:storage` hook
40- queryContent ( '/non-existing-path' ) . findOne ( )
41- }
25+ const syncPreviewFiles = async ( files : PreviewFile [ ] ) => {
26+ const previewToken = window . sessionStorage . getItem ( 'previewToken' ) as string
4227
43- const syncPreviewFiles = async ( contentStorage : Storage , files : PreviewFile [ ] ) => {
44- const previewToken = window . sessionStorage . getItem ( 'previewToken' )
4528 // Remove previous preview data
46- const keys : string [ ] = await contentStorage . getKeys ( `${ previewToken } :` )
47- await Promise . all ( keys . map ( key => contentStorage . removeItem ( key ) ) )
29+ removeAllContentItems ( previewToken )
4830
4931 // Set preview meta
50- const sources = new Set < string > ( files . map ( file => file . parsed ! . _id . split ( ':' ) . shift ( ) ! ) )
51- await contentStorage . setItem ( `${ previewToken } $` , JSON . stringify ( { ignoreSources : Array . from ( sources ) } ) )
32+ setPreviewMetaItems ( previewToken , files )
5233
5334 // Handle content files
5435 await Promise . all (
55- files . map ( ( item ) => {
56- contentPathMap [ item . parsed ! . _path ! ] = item . parsed !
57- return contentStorage . setItem ( `${ previewToken } :${ item . parsed ! . _id } ` , JSON . stringify ( item . parsed ) )
36+ files . map ( ( file ) => {
37+ updateContentItem ( previewToken , file )
5838 } ) ,
5939 )
6040 }
@@ -94,7 +74,7 @@ export const useStudio = () => {
9474
9575 // Handle content files
9676 const contentFiles = mergedFiles . filter ( item => ! ( [ StudioConfigFiles . appConfig , StudioConfigFiles . nuxtConfig ] . includes ( item . path ) ) )
97- await syncPreviewFiles ( storage . value , contentFiles )
77+ await syncPreviewFiles ( contentFiles )
9878
9979 const appConfig = mergedFiles . find ( item => item . path === StudioConfigFiles . appConfig )
10080 syncPreviewAppConfig ( appConfig ?. parsed as ParsedContent )
@@ -130,58 +110,12 @@ export const useStudio = () => {
130110 } ) . mount ( el )
131111 }
132112
133- // Content Helpers
134- const findContentWithId = async ( path : string ) : Promise < ParsedContent | null > => {
135- const previewToken = window . sessionStorage . getItem ( 'previewToken' )
136- if ( ! path ) {
137- return null
138- }
139- path = path . replace ( / \/ $ / , '' )
140- let content = await storage . value ?. getItem ( `${ previewToken } :${ path } ` )
141- if ( ! content ) {
142- content = await storage . value ?. getItem ( `cached:${ path } ` )
143- }
144- if ( ! content ) {
145- content = content = await storage . value ?. getItem ( path )
146- }
147-
148- // try finding content from contentPathMap
149- if ( ! content ) {
150- content = contentPathMap [ path || '/' ]
151- }
152-
153- return content as ParsedContent
154- }
155-
156- const updateContent = ( content : PreviewFile ) => {
157- const previewToken = window . sessionStorage . getItem ( 'previewToken' )
158- if ( ! storage . value ) return
159-
160- contentPathMap [ content . parsed ! . _path ! ] = content . parsed !
161- storage . value . setItem ( `${ previewToken } :${ content . parsed ?. _id } ` , JSON . stringify ( content . parsed ) )
162- }
163-
164- const removeContentWithId = async ( path : string ) => {
165- const previewToken = window . sessionStorage . getItem ( 'previewToken' )
166- const content = await findContentWithId ( path )
167- await storage . value ?. removeItem ( `${ previewToken } :${ path } ` )
168-
169- if ( content ) {
170- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
171- delete contentPathMap [ content . _path ! ]
172- const nonDraftContent = await findContentWithId ( content . _id )
173- if ( nonDraftContent ) {
174- contentPathMap [ nonDraftContent . _path ! ] = nonDraftContent
175- }
176- }
177- }
178-
179113 const requestRerender = async ( ) => {
180114 if ( contentConfig ?. documentDriven ) {
181115 const { pages } = callWithNuxt ( nuxtApp , useContentState )
182116
183117 const contents = await Promise . all ( Object . keys ( pages . value ) . map ( async ( key ) => {
184- return await findContentWithId ( pages . value [ key ] ?. _id ?? key )
118+ return await findContentItem ( pages . value [ key ] ?. _id ?? key )
185119 } ) )
186120
187121 pages . value = contents . reduce ( ( acc , item , index ) => {
@@ -196,19 +130,6 @@ export const useStudio = () => {
196130 }
197131
198132 return {
199- apiURL,
200- contentStorage : storage ,
201-
202- syncPreviewFiles,
203- syncPreviewAppConfig,
204- requestPreviewSynchronization,
205-
206- findContentWithId,
207- updateContent,
208- removeContentWithId,
209-
210- requestRerender,
211-
212133 mountPreviewUI,
213134 initiateIframeCommunication,
214135 }
@@ -258,7 +179,7 @@ export const useStudio = () => {
258179
259180 switch ( type ) {
260181 case 'nuxt-studio:editor:file-selected' : {
261- const content = await findContentWithId ( payload . path )
182+ const content = await findContentItem ( payload . path )
262183 if ( ! content ) {
263184 // Do not navigate to another page if content is not found
264185 // This makes sure that user stays on the same page when navigation through directories in the editor
@@ -273,21 +194,19 @@ export const useStudio = () => {
273194 }
274195 break
275196 }
197+ case 'nuxt-studio:editor:media-changed' :
276198 case 'nuxt-studio:editor:file-changed' : {
199+ const previewToken = window . sessionStorage . getItem ( 'previewToken' ) as string
277200 const { additions = [ ] , deletions = [ ] } = payload as FileChangeMessagePayload
278201 for ( const addition of additions ) {
279- await updateContent ( addition )
202+ await updateContentItem ( previewToken , addition )
280203 }
281204 for ( const deletion of deletions ) {
282- await removeContentWithId ( deletion . path )
205+ await removeContentItem ( previewToken , deletion . path )
283206 }
284207 requestRerender ( )
285208 break
286209 }
287- case 'nuxt-studio:preview:sync' : {
288- syncPreview ( payload )
289- break
290- }
291210 case 'nuxt-studio:config:file-changed' : {
292211 const { additions = [ ] , deletions = [ ] } = payload as FileChangeMessagePayload
293212
0 commit comments