mirror of
https://github.com/supabase/supabase.git
synced 2026-05-09 10:19:50 -04:00
35905e70d5
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Logo field now accepts/editable logo URL, plus a new storage-based Logo Picker to select or remove images from project storage. * Full storage picker: browse buckets, columns/list views, search, drag‑and‑drop uploads, file previews (image/audio/video), and single-file selection with responsive mobile/desktop layouts. * **Refactor** * Logo submission streamlined to send the provided URL directly (legacy file-read/upload flow removed). <!-- end of auto-generated comment: release notes by coderabbit.ai -->
87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import { createContext, PropsWithChildren, useContext, useMemo } from 'react'
|
|
import { proxy, useSnapshot } from 'valtio'
|
|
|
|
import { StorageItemWithColumn } from '@/components/interfaces/Storage/Storage.types'
|
|
import type { Bucket } from '@/data/storage/buckets-query'
|
|
|
|
function createBucketFilePickerState({
|
|
bucket,
|
|
maxFiles,
|
|
acceptedFileExtensions,
|
|
}: {
|
|
bucket: Bucket
|
|
maxFiles: number
|
|
acceptedFileExtensions?: string[]
|
|
}) {
|
|
const state = proxy({
|
|
bucket: bucket,
|
|
maxFiles: maxFiles,
|
|
acceptedFileExtensions: acceptedFileExtensions,
|
|
|
|
columns: [] as string[],
|
|
popColumn: () => {
|
|
const lastColumnIndex = state.columns.length - 1
|
|
state.columns = state.columns.slice(0, lastColumnIndex)
|
|
},
|
|
popColumnAtIndex: (index: number) => {
|
|
state.columns = state.columns.slice(0, index)
|
|
},
|
|
pushColumnAtIndex: (column: string, index: number) => {
|
|
state.columns = state.columns.slice(0, index).concat([column])
|
|
},
|
|
|
|
selectedItems: [] as StorageItemWithColumn[],
|
|
setSelectedItems: (items: StorageItemWithColumn[]) => (state.selectedItems = items),
|
|
clearSelectedItems: (columnIndex?: number) => {
|
|
if (columnIndex !== undefined) {
|
|
state.selectedItems = state.selectedItems.filter((item) => item.columnIndex !== columnIndex)
|
|
} else {
|
|
state.selectedItems = []
|
|
}
|
|
},
|
|
|
|
itemSearchString: '',
|
|
setItemSearchString: (value: string) => (state.itemSearchString = value),
|
|
|
|
selectedFilePreview: undefined as StorageItemWithColumn | undefined,
|
|
setSelectedFilePreview: (file?: StorageItemWithColumn) => (state.selectedFilePreview = file),
|
|
})
|
|
|
|
return state
|
|
}
|
|
|
|
export type BucketFilePickerState = ReturnType<typeof createBucketFilePickerState>
|
|
|
|
const DEFAULT_STATE_CONFIG = {
|
|
bucket: {} as Bucket,
|
|
maxFiles: 1 as const,
|
|
}
|
|
|
|
const BucketFilePickerStateContext = createContext<BucketFilePickerState>(
|
|
createBucketFilePickerState(DEFAULT_STATE_CONFIG)
|
|
)
|
|
|
|
export const BucketFilePickerStateContextProvider = ({
|
|
bucket,
|
|
maxFiles,
|
|
acceptedFileExtensions,
|
|
children,
|
|
}: PropsWithChildren<{ bucket: Bucket; maxFiles: number; acceptedFileExtensions?: string[] }>) => {
|
|
const state = useMemo(
|
|
() => createBucketFilePickerState({ bucket, maxFiles, acceptedFileExtensions }),
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
[bucket, maxFiles, acceptedFileExtensions?.join(',')]
|
|
)
|
|
|
|
return (
|
|
<BucketFilePickerStateContext.Provider value={state}>
|
|
{children}
|
|
</BucketFilePickerStateContext.Provider>
|
|
)
|
|
}
|
|
|
|
export function useBucketFilePickerStateSnapshot(options?: Parameters<typeof useSnapshot>[1]) {
|
|
const state = useContext(BucketFilePickerStateContext)
|
|
return useSnapshot(state, options) as BucketFilePickerState
|
|
}
|