@@ -5,36 +5,38 @@ import {
55 objectIdToWalrusSiteUrl
66} from '@cmdoss/site-builder'
77import {
8- PublishButton ,
98 type SiteMetadata ,
109 type SiteMetadataUpdate ,
1110 useZenFsWorkspace ,
1211 useZenfsFilesQuery
1312} from '@cmdoss/site-builder-react'
14- import { AnimatedBackground } from '@/components/AnimatedBackground'
15- import { FileExplorer } from '@/components/file-explorer/file-explorer'
13+ import AnimatedBackground from '@/components/AnimatedBackground'
1614import { Introduction } from '@/components/Introduction'
17- import { Button } from '@/components/ui/button'
1815import { CardContent } from '@/components/ui/card'
19- import {
20- Tooltip ,
21- TooltipContent ,
22- TooltipTrigger
23- } from '@/components/ui/tooltip'
16+ import { useNetworkConfig } from '@/configs/networkConfig'
17+ import { $siteId } from '@/stores/siteStore'
2418import '@cmdoss/site-builder-react/styles.css'
2519import {
2620 useCurrentAccount ,
2721 useSignAndExecuteTransaction ,
2822 useSuiClient
2923} from '@mysten/dapp-kit'
24+ import { useStore } from '@nanostores/react'
3025import { useQueryClient } from '@tanstack/react-query'
31- import { useCallback , useEffect } from 'react'
26+ import { useCallback , useEffect , useState } from 'react'
3227import { toast } from 'sonner'
33- import { testFiles } from './files'
28+ import AssetsSection from '@/components/AssetsSection'
29+ import PublishedSiteInfo from '@/components/PublishedSiteInfo'
30+ import PublishSection from '@/components/PublishSection'
31+ import { testFilesSet1 , testFilesSet2 } from './files'
3432
3533export default function Home ( ) {
3634 const queryClient = useQueryClient ( )
3735 const suiClient = useSuiClient ( )
36+ const siteId = useStore ( $siteId )
37+ const networkConfig = useNetworkConfig ( )
38+ const [ isAddingFiles , setIsAddingFiles ] = useState ( false )
39+ const [ isClearingWorkspace , setIsClearingWorkspace ] = useState ( false )
3840
3941 const { loading, fileManager : fm } = useZenFsWorkspace (
4042 '/sites/site-01' ,
@@ -64,7 +66,7 @@ export default function Home() {
6466 if ( ! fm ) throw new Error ( 'FileManager not initialized' )
6567
6668 try {
67- for ( const [ path , content ] of Object . entries ( testFiles ) ) {
69+ for ( const [ path , content ] of Object . entries ( testFilesSet1 ) ) {
6870 console . log ( 'Adding test file:' , path )
6971 await fm . writeFile ( path , new TextEncoder ( ) . encode ( content ) )
7072 }
@@ -78,13 +80,27 @@ export default function Home() {
7880 async ( site : SiteMetadataUpdate ) : Promise < SiteMetadata > => {
7981 // Playground has no backend; return the provided site to satisfy types
8082 // but convert imageUrl to string if it's a File object
81- const imageUrl =
82- typeof site . imageUrl === 'string'
83- ? site . imageUrl
84- : typeof site . imageUrl === 'object'
85- ? URL . createObjectURL ( site . imageUrl )
86- : ''
87- return { ...site , imageUrl }
83+ let imageUrl = ''
84+ if ( typeof site . imageUrl === 'string' ) {
85+ imageUrl = site . imageUrl
86+ } else if ( site . imageUrl instanceof File ) {
87+ imageUrl = await new Promise < string > ( ( resolve , reject ) => {
88+ const reader = new FileReader ( )
89+ reader . onload = ( ) => resolve ( reader . result as string )
90+ reader . onerror = reject
91+ reader . readAsDataURL ( site . imageUrl as File )
92+ } )
93+ }
94+
95+ if ( site . id ) {
96+ console . log ( '💾 Storing published site ID:' , site . id )
97+ $siteId . set ( site . id ) // Store published site ID persistently
98+ }
99+
100+ const result : SiteMetadata = { ...site , imageUrl }
101+ console . log ( '💾 Updated site metadata:' , result )
102+
103+ return result
88104 } ,
89105 [ ]
90106 )
@@ -94,28 +110,45 @@ export default function Home() {
94110 toast . error ( msg )
95111 } , [ ] )
96112
97- const addTestFiles = useCallback ( async ( ) => {
98- if ( ! fm ) {
99- toast . error ( 'FileManager not initialized' )
100- return
101- }
102- try {
103- for ( const [ path , content ] of Object . entries ( testFiles ) ) {
104- console . log ( 'Adding test file:' , path )
105- await fm . writeFile ( path , new TextEncoder ( ) . encode ( content ) )
113+ const addTestFiles = useCallback (
114+ async ( fileSet : Record < string , string > , setName : string ) => {
115+ if ( ! fm ) {
116+ toast . error ( 'FileManager not initialized' )
117+ return
106118 }
107- await refetchAssets ( )
108- toast . success ( 'Test files added' )
109- } catch ( error ) {
110- console . error ( 'Failed to create test files:' , error )
111- }
112- } , [ fm , refetchAssets ] )
119+ setIsAddingFiles ( true )
120+ try {
121+ for ( const [ path , content ] of Object . entries ( fileSet ) ) {
122+ console . log ( 'Adding test file:' , path )
123+ await fm . writeFile ( path , new TextEncoder ( ) . encode ( content ) )
124+ }
125+ await refetchAssets ( )
126+ toast . success ( `${ setName } added` )
127+ } catch ( error ) {
128+ console . error ( 'Failed to create test files:' , error )
129+ } finally {
130+ setIsAddingFiles ( false )
131+ }
132+ } ,
133+ [ fm , refetchAssets ]
134+ )
135+
136+ const addTestFilesSet1 = useCallback (
137+ ( ) => addTestFiles ( testFilesSet1 , 'Sample Files Set #1' ) ,
138+ [ addTestFiles ]
139+ )
140+
141+ const addTestFilesSet2 = useCallback (
142+ ( ) => addTestFiles ( testFilesSet2 , 'Sample Files Set #2' ) ,
143+ [ addTestFiles ]
144+ )
113145
114146 const clearWorkspace = useCallback ( async ( ) => {
115147 if ( ! fm ) {
116148 toast . error ( 'FileManager not initialized' )
117149 return
118150 }
151+ setIsClearingWorkspace ( true )
119152 try {
120153 const files = await fm . listFiles ( )
121154 for ( const file of files ) {
@@ -126,6 +159,8 @@ export default function Home() {
126159 } catch ( error ) {
127160 console . error ( 'Failed to clear workspace:' , error )
128161 toast . error ( 'Failed to clear workspace' )
162+ } finally {
163+ setIsClearingWorkspace ( false )
129164 }
130165 } , [ fm , refetchAssets ] )
131166
@@ -141,77 +176,37 @@ export default function Home() {
141176 < div className = "flex flex-col items-center gap-6 w-full mx-auto" >
142177 < CardContent className = "relative w-full" >
143178 < h1 className = "mb-1" > Assets</ h1 >
144- { loading && (
145- < div className = "absolute inset-0 bg-background/80 backdrop-blur-sm z-10 flex items-center justify-center rounded-lg" >
146- < div className = "flex items-center gap-2" >
147- < span className = "text-sm text-muted-foreground" >
148- Loading file system...
149- </ span >
150- </ div >
151- </ div >
152- ) }
153- { ! assets . length ? (
154- < div className = "space-y-4" >
155- < div className = "pt-2" >
156- < Button
157- onClick = { addTestFiles }
158- className = "w-full bg-[#97f0e5] text-[#0C0F1D] hover:bg-[#97f0e5]/90 border border-[#97F0E599]"
159- >
160- Add Test Files (HTML + SVG)
161- </ Button >
162- < p className = "text-xs text-gray-300 mt-2 text-center" >
163- Creates index.html with Hello World and a glass of water SVG
164- </ p >
165- </ div >
166- </ div >
167- ) : (
168- < div className = "space-y-4" >
169- < FileExplorer className = "h-[300px]" assets = { assets } />
170-
171- < Button
172- onClick = { clearWorkspace }
173- className = "w-full text-[#97f0e5] hover:opacity-80 border border-[#97F0E599]"
174- >
175- Clear Files
176- </ Button >
177- </ div >
178- ) }
179+
180+ < AssetsSection
181+ loading = { loading }
182+ assets = { assets }
183+ onAddTestFilesSet1 = { addTestFilesSet1 }
184+ onAddTestFilesSet2 = { addTestFilesSet2 }
185+ onClearWorkspace = { clearWorkspace }
186+ isAddingFiles = { isAddingFiles }
187+ isClearingWorkspace = { isClearingWorkspace }
188+ />
179189
180190 < hr className = "my-4 border-t border-neutral-400 dark:border-neutral-700" />
181- < div className = " flex flex-col gap-2" >
182- { ! currentAccount ? (
183- < Tooltip >
184- < TooltipTrigger asChild >
185- < div >
186- < Button
187- className = "w-full bg-[#97f0e5] text-[#0C0F1D] hover:bg-[#97f0e5]/90 border border-[#97F0E599]"
188- disabled
189- >
190- Publish
191- </ Button >
192- </ div >
193- </ TooltipTrigger >
194- < TooltipContent sideOffset = { 6 } className = "text-sm" >
195- { ! assets . length
196- ? 'Add files to publish your site'
197- : ! currentAccount
198- ? 'Please connect your wallet to publish'
199- : '' }
200- </ TooltipContent >
201- </ Tooltip >
202- ) : (
203- < PublishButton
204- onPrepareAssets = { handlePrepareAssetsForBuilder }
205- onUpdateSiteMetadata = { handleUpdateSiteMetadataForBuilder }
206- onError = { handleBuilderError }
207- currentAccount = { currentAccount }
208- clients = { { suiClient, queryClient } }
209- signAndExecuteTransaction = { signAndExecuteTransaction }
210- >
211- < Button className = "w-full bg-[#97f0e5] text-[#0C0F1D] hover:bg-[#97f0e5]/90 border border-[#97F0E599]" >
212- Publish
213- </ Button >
214- </ PublishButton >
191+
192+ < div className = "flex flex-col gap-2" >
193+ < PublishSection
194+ siteId = { siteId }
195+ currentAccount = { currentAccount }
196+ assets = { assets }
197+ onPrepareAssets = { handlePrepareAssetsForBuilder }
198+ onUpdateSiteMetadata = { handleUpdateSiteMetadataForBuilder }
199+ onError = { handleBuilderError }
200+ signAndExecuteTransaction = { signAndExecuteTransaction }
201+ clients = { { suiClient, queryClient } }
202+ />
203+
204+ { siteId && (
205+ < PublishedSiteInfo
206+ siteId = { siteId }
207+ network = { networkConfig . network }
208+ onClearSiteId = { ( ) => $siteId . set ( '' ) }
209+ />
215210 ) }
216211 </ div >
217212 </ CardContent >
0 commit comments