From 0d10a01880fa7319c9fc1d3e1de9c5a36fb2543a Mon Sep 17 00:00:00 2001 From: 0xzion <0xzion.penx@gmail.com> Date: Sun, 26 May 2024 18:09:56 +0800 Subject: [PATCH] feat: can render database --- apps/desktop/package.json | 1 + .../src/common/installBuiltinExtension.ts | 15 +-- .../CommandPalette/CommandApp/CommandApp.tsx | 2 +- .../CommandPalette/CommandApp/DatabaseApp.tsx | 11 -- .../CommandApp/DatabaseApp/DatabaseApp.tsx | 22 +++ .../CommandApp/DatabaseApp/DatabaseDetail.tsx | 125 ++++++++++++++++++ .../CommandApp/DatabaseApp/FieldIcon.tsx | 44 ++++++ .../CommandApp/DatabaseApp/RowForm.tsx | 68 ++++++++++ .../CommandPalette/CommandComponents.ts | 2 + .../CommandPalette/CommandPaletteFooter.tsx | 5 +- .../CommandPalette/DatabaseName.tsx | 21 +++ .../CommandPalette/ListItemIcon.tsx | 48 ++++++- .../components/CommandPalette/ListItemUI.tsx | 13 +- .../components/CommandPalette/SearchBar.tsx | 32 ++++- apps/desktop/src/hooks/useCommandPosition.ts | 8 ++ apps/desktop/src/hooks/useCurrentDatabase.ts | 11 ++ apps/desktop/src/hooks/useHandleSelect.ts | 10 +- apps/desktop/src/hooks/useItems.ts | 32 ++++- packages/app/src/Workbench/PanelItem.tsx | 2 - .../AccountSettings/AccountSettings.tsx | 2 +- .../app/src/Workbench/Sidebar/Sidebar.tsx | 4 +- packages/app/src/Workbench/Workbench.tsx | 2 +- .../cell-fields/src/fields/SingleSelect.tsx | 2 +- packages/local-db/src/libs/getRandomColor.ts | 2 +- packages/model/src/Node.ts | 6 + packages/penx/src/components/ListBuilder.ts | 18 ++- pnpm-lock.yaml | 4 + 27 files changed, 457 insertions(+), 55 deletions(-) delete mode 100644 apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp.tsx create mode 100644 apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/DatabaseApp.tsx create mode 100644 apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/DatabaseDetail.tsx create mode 100644 apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/FieldIcon.tsx create mode 100644 apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/RowForm.tsx create mode 100644 apps/desktop/src/components/CommandPalette/DatabaseName.tsx create mode 100644 apps/desktop/src/hooks/useCurrentDatabase.ts diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 1dfe74de2..740ea624f 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -22,6 +22,7 @@ "@penx/api": "workspace:*", "@penx/app": "workspace:*", "@penx/cmdk": "workspace:*", + "@penx/cell-fields": "workspace:*", "@penx/constants": "workspace:*", "@penx/encryption": "workspace:*", "@penx/event": "workspace:*", diff --git a/apps/desktop/src/common/installBuiltinExtension.ts b/apps/desktop/src/common/installBuiltinExtension.ts index dc5878bef..f4af007c7 100644 --- a/apps/desktop/src/common/installBuiltinExtension.ts +++ b/apps/desktop/src/common/installBuiltinExtension.ts @@ -18,9 +18,9 @@ export async function installBuiltinExtension() { isDeveloping: false, commands: [ { - name: 'database', - title: 'Database', - icon: '/icons/copy.svg', + name: 'marketplace', + title: 'marketplace', + icon: '/icons/marketplace.svg', subtitle: '', description: '', code: '', @@ -35,15 +35,6 @@ export async function installBuiltinExtension() { code: '', isBuiltIn: true, }, - { - name: 'marketplace', - title: 'marketplace', - icon: '/icons/marketplace.svg', - subtitle: '', - description: '', - code: '', - isBuiltIn: true, - }, ], createdAt: new Date(), updatedAt: new Date(), diff --git a/apps/desktop/src/components/CommandPalette/CommandApp/CommandApp.tsx b/apps/desktop/src/components/CommandPalette/CommandApp/CommandApp.tsx index d4d2accf1..776ec9d45 100644 --- a/apps/desktop/src/components/CommandPalette/CommandApp/CommandApp.tsx +++ b/apps/desktop/src/components/CommandPalette/CommandApp/CommandApp.tsx @@ -6,7 +6,7 @@ import { Spinner } from 'uikit' import { Markdown } from '~/components/Markdown' import { CommandAppUI } from '~/hooks/useCommandAppUI' import { ClipboardHistoryApp } from './ClipboardHistoryApp' -import { DatabaseApp } from './DatabaseApp' +import { DatabaseApp } from './DatabaseApp/DatabaseApp' import { ListApp } from './ListApp' import { MarketplaceApp } from './MarketplaceApp/MarketplaceApp' import { TodayApp } from './TodayApp' diff --git a/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp.tsx b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp.tsx deleted file mode 100644 index 6fd491020..000000000 --- a/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Box } from '@fower/react' - -export function DatabaseApp() { - return ( - - - Database List - - - ) -} diff --git a/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/DatabaseApp.tsx b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/DatabaseApp.tsx new file mode 100644 index 000000000..bebc97dbe --- /dev/null +++ b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/DatabaseApp.tsx @@ -0,0 +1,22 @@ +import { useQuery } from '@tanstack/react-query' +import { db } from '@penx/local-db' +import { useCurrentDatabase } from '~/hooks/useCurrentDatabase' +import { useSearch } from '~/hooks/useSearch' +import { StyledCommandGroup } from '../../CommandComponents' +import { DatabaseDetail } from './DatabaseDetail' + +export function DatabaseApp() { + const { database } = useCurrentDatabase() + const { search } = useSearch() + + const { data, isLoading } = useQuery({ + queryKey: ['database', database.id], + queryFn: () => db.getDatabase(database.id), + }) + + if (isLoading || !data) { + return + } + + return +} diff --git a/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/DatabaseDetail.tsx b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/DatabaseDetail.tsx new file mode 100644 index 000000000..60faf5a12 --- /dev/null +++ b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/DatabaseDetail.tsx @@ -0,0 +1,125 @@ +import { useEffect, useMemo } from 'react' +import { Box } from '@fower/react' +import { Divider } from 'uikit' +import { + ICellNode, + IColumnNode, + IDatabaseNode, + IOptionNode, + IRowNode, + IViewNode, +} from '@penx/model-types' +import { mappedByKey } from '@penx/shared' +import { useValue } from '~/hooks/useValue' +import { StyledCommandEmpty, StyledCommandGroup } from '../../CommandComponents' +import { ListItemUI } from '../../ListItemUI' +import { RowForm } from './RowForm' + +interface Props { + text: string + database: IDatabaseNode + views: IViewNode[] + columns: IColumnNode[] + rows: IRowNode[] + cells: ICellNode[] + options: IOptionNode[] +} + +interface Item { + row: IRowNode + cell: ICellNode + rowCells: ICellNode[] +} + +export function DatabaseDetail(props: Props) { + const { value, setValue } = useValue() + const { text, ...rest } = props + const { columns, rows, views, cells } = rest + const currentView = views[0] + const { viewColumns = [] } = currentView.props + const columnMap = mappedByKey(columns, 'id') + const sortedColumns = viewColumns.map(({ columnId }) => columnMap[columnId]) + + const filteredRows: Item[] = useMemo(() => { + const items = rows + .map((row) => { + const rowCells = cells.filter((cell) => cell.props.rowId === row.id) + + if (!text) { + const cell = rowCells.find( + (cell) => cell.props.columnId === sortedColumns[0].id, + )! + return { row, rowCells, cell } + } + + const cell = rowCells.find((cell) => { + // console.log('cell-----:', cell.props.data) + const data = String(cell.props?.data || '').toLowerCase() + return data.includes(text.toLowerCase()) + })! + return { row, rowCells, cell } + }) + .filter((item) => !!item.cell) + .slice(0, 20) + return items + }, [rows, cells, text, sortedColumns]) + + useEffect(() => { + if (!isUuidV4(value) && filteredRows.length) { + setValue(filteredRows[0].row.id) + } + }, [filteredRows, value, setValue]) + + // console.log('=======filteredRows:', filteredRows, 'value:', value) + const currentItem = filteredRows.find((item) => item.row.id === value) + + if (!filteredRows.length) + return ( + + No results found. + + ) + + return ( + + + {filteredRows.map((item, index) => { + // console.log('=======item:', item) + + const listItem = { + title: dataToString(item.cell.props.data), + } + return ( + + ) + })} + + + + + + {currentItem && } + + + ) +} + +function dataToString(data: any) { + if (!data) return 'Untitled' + if (typeof data === 'string') return data + if (typeof data === 'number') return data.toString() + if (Array.isArray(data)) return data.join(',') + return JSON.stringify(data, null) +} + +function isUuidV4(uuid: string): boolean { + const uuidV4Regex = + /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i + return uuidV4Regex.test(uuid) +} diff --git a/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/FieldIcon.tsx b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/FieldIcon.tsx new file mode 100644 index 000000000..60be63437 --- /dev/null +++ b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/FieldIcon.tsx @@ -0,0 +1,44 @@ +import { Box } from '@fower/react' +import { + CalendarDays, + CheckCircle2, + Hash, + Home, + Key, + Link, + ListChecks, + Text, +} from 'lucide-react' +import { FieldType } from '@penx/model-types' + +interface Props { + index?: number + fieldType: `${FieldType}` + size?: number +} + +export const FieldIcon = ({ fieldType, size = 16, index }: Props) => { + const iconsMap: Record = { + [FieldType.TEXT]: Text, + [FieldType.NUMBER]: Hash, + [FieldType.URL]: Link, + [FieldType.PASSWORD]: Key, + [FieldType.SINGLE_SELECT]: CheckCircle2, + [FieldType.MULTIPLE_SELECT]: ListChecks, + [FieldType.MARKDOWN]: Text, + [FieldType.DATE]: CalendarDays, + [FieldType.CREATED_AT]: CalendarDays, + [FieldType.UPDATED_AT]: CalendarDays, + } + let Icon = iconsMap[fieldType] + + if (index === 0) Icon = Home + + if (Icon) + return ( + + + + ) + return null +} diff --git a/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/RowForm.tsx b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/RowForm.tsx new file mode 100644 index 000000000..620262970 --- /dev/null +++ b/apps/desktop/src/components/CommandPalette/CommandApp/DatabaseApp/RowForm.tsx @@ -0,0 +1,68 @@ +import { forwardRef } from 'react' +import { Box } from '@fower/react' +import { CellField } from '@penx/cell-fields' +import { + ICellNode, + IColumnNode, + IDatabaseNode, + IOptionNode, + IRowNode, + IViewNode, +} from '@penx/model-types' +import { mappedByKey } from '@penx/shared' +import { FieldIcon } from './FieldIcon' + +interface Props { + rowId: string + database: IDatabaseNode + views: IViewNode[] + columns: IColumnNode[] + rows: IRowNode[] + cells: ICellNode[] + options: IOptionNode[] +} + +export const RowForm = forwardRef( + function TagForm(props, ref) { + const { columns, views, cells, rowId } = props + + // console.log('========cells;', cells, 'rowId:', rowId) + + const currentView = views[0] + + const columnMap = mappedByKey(columns, 'id') + const { viewColumns = [] } = currentView.props + const sortedColumns = viewColumns.map(({ columnId }) => columnMap[columnId]) + + const rowCells = sortedColumns.map((column) => { + return cells.find( + (cell) => + cell.props.rowId === rowId && cell.props.columnId === column.id, + )! + }) + + // console.log('========rowCells:', rowCells) + + return ( + + {rowCells.map((cell, index) => { + // console.log('=====cell:', cell) + + const column = columns.find((col) => col.id === cell.props.columnId)! + + if (!column) return null + + return ( + + + + {column.props.displayName} + + + + ) + })} + + ) + }, +) diff --git a/apps/desktop/src/components/CommandPalette/CommandComponents.ts b/apps/desktop/src/components/CommandPalette/CommandComponents.ts index a34cf5c71..d57f96673 100644 --- a/apps/desktop/src/components/CommandPalette/CommandComponents.ts +++ b/apps/desktop/src/components/CommandPalette/CommandComponents.ts @@ -10,3 +10,5 @@ export const StyledCommandInput = styled(Command.Input) export const StyledCommandList = styled(Command.List) export const StyledCommandGroup = styled(Command.Group) + +export const StyledCommandEmpty = styled(Command.Empty) diff --git a/apps/desktop/src/components/CommandPalette/CommandPaletteFooter.tsx b/apps/desktop/src/components/CommandPalette/CommandPaletteFooter.tsx index 8c2e001b4..d9f8c23c8 100644 --- a/apps/desktop/src/components/CommandPalette/CommandPaletteFooter.tsx +++ b/apps/desktop/src/components/CommandPalette/CommandPaletteFooter.tsx @@ -26,10 +26,9 @@ export const CommandPaletteFooter = ({ footerHeight }: Props) => { px4 toBetween > - {currentCommand && ( + {currentCommand && currentCommand.data.extensionIcon ? ( - )} - {!currentCommand && ( + ) : ( { + const { database } = useCurrentDatabase() + return ( + + # {database.props.name} + + ) +} diff --git a/apps/desktop/src/components/CommandPalette/ListItemIcon.tsx b/apps/desktop/src/components/CommandPalette/ListItemIcon.tsx index 64db241b1..c407f4aba 100644 --- a/apps/desktop/src/components/CommandPalette/ListItemIcon.tsx +++ b/apps/desktop/src/components/CommandPalette/ListItemIcon.tsx @@ -1,13 +1,21 @@ import SVG from 'react-inlinesvg' import { Box, css, FowerHTMLProps } from '@fower/react' import Image from 'next/image' +import { isObjectIcon } from 'penx' +import { getRandomColor } from '@penx/local-db' interface ListItemIconProps extends FowerHTMLProps<'div'> { icon?: string | number size?: number + bg?: string } -export function ListItemIcon({ icon, size = 20, ...rest }: ListItemIconProps) { +export function ListItemIcon({ + icon, + bg, + size = 20, + ...rest +}: ListItemIconProps) { if (!icon) { return ( @@ -15,13 +23,49 @@ export function ListItemIcon({ icon, size = 20, ...rest }: ListItemIconProps) { } if (typeof icon === 'number') { + const colorName = bg || getRandomColor('500') + + const arr = [ + colorName.replace('500', '400'), + colorName, + colorName.replace('500', '600'), + ] + return ( - + {icon} ) } + // TODO: handle other icon value + if (isObjectIcon(icon)) { + if (icon.value === '#') { + return ( + + {icon.value} + + ) + } + } + if (icon.startsWith('/')) { return ( , 'onSelect'> { index: number + value?: any item: IListItem isListApp?: boolean titleLayout?: 'column' | 'row' + showIcon?: boolean onSelect?: (item: IListItem) => void } @@ -20,6 +22,8 @@ export const ListItemUI = ({ index, titleLayout = 'row', isListApp = false, + showIcon = true, + value, ...rest }: ListItemUIProps) => { const { currentCommand } = useCurrentCommand() @@ -53,7 +57,8 @@ export const ListItemUI = ({ gap4 roundedLG black - value={title} + value={value || title} + // keywords={[title]} onSelect={() => { onSelect?.(item) }} @@ -63,7 +68,7 @@ export const ListItemUI = ({ {...rest} > - + {showIcon && } {title} @@ -71,9 +76,9 @@ export const ListItemUI = ({ - {!!item.data?.commandName && ( + {!!item.data?.type && ( - Command + {item.data?.type} )} {item?.extra && ( diff --git a/apps/desktop/src/components/CommandPalette/SearchBar.tsx b/apps/desktop/src/components/CommandPalette/SearchBar.tsx index f6bacbc9f..061e752ea 100644 --- a/apps/desktop/src/components/CommandPalette/SearchBar.tsx +++ b/apps/desktop/src/components/CommandPalette/SearchBar.tsx @@ -6,8 +6,10 @@ import { useCommandPosition } from '~/hooks/useCommandPosition' import { useCurrentCommand } from '~/hooks/useCurrentCommand' import { useCommands, useItems } from '~/hooks/useItems' import { useSearch } from '~/hooks/useSearch' +import { useValue } from '~/hooks/useValue' import { ToggleModeButton } from '../ToggleModeButton' import { StyledCommandInput } from './CommandComponents' +import { DatabaseName } from './DatabaseName' import { SearchBarFilter } from './SearchBarFilter' interface Props { @@ -18,10 +20,22 @@ export const SearchBar = ({ searchBarHeight }: Props) => { const { setItems } = useItems() const { commands } = useCommands() const ref = useRef() - const { isCommandApp, isCommandAppDetail, backToRoot, setPosition } = - useCommandPosition() + const { + isCommandApp, + isCommandAppDetail, + backToRoot, + backToCommandApp, + setPosition, + } = useCommandPosition() const { currentCommand } = useCurrentCommand() + const currentCommandName = currentCommand?.data?.commandName + const isMarketplaceDetail = + currentCommandName === 'marketplace' && isCommandAppDetail + + const isDatabaseDetail = + currentCommandName === 'database' && isCommandAppDetail + return ( { cursorPointer onClick={() => { if (isCommandAppDetail) { - setPosition('COMMAND_APP') + backToCommandApp() } else { backToRoot() + setSearch('') } }} > )} - {!isCommandAppDetail && ( + + {isDatabaseDetail && } + + {!isMarketplaceDetail && ( { onKeyDown={(e) => { if (e.key === 'Backspace' || e.key === 'delete') { if (!search && isCommandApp) { - backToRoot() + if (isCommandAppDetail) { + backToCommandApp() + } else { + backToRoot() + } } } if (e.key === 'Enter') { diff --git a/apps/desktop/src/hooks/useCommandPosition.ts b/apps/desktop/src/hooks/useCommandPosition.ts index 7f5958ff0..1fe13083f 100644 --- a/apps/desktop/src/hooks/useCommandPosition.ts +++ b/apps/desktop/src/hooks/useCommandPosition.ts @@ -20,6 +20,13 @@ export function useCommandPosition() { workerStore.currentWorker.postMessage('BACK_TO_ROOT') } } + + function backToCommandApp() { + console.log('name....dd COMMAND_APP') + + setPosition('COMMAND_APP') + } + return { isRoot: position === 'ROOT', isCommandApp: @@ -27,6 +34,7 @@ export function useCommandPosition() { isCommandAppDetail: position === 'COMMAND_APP_DETAIL', position, backToRoot, + backToCommandApp, setPosition, } } diff --git a/apps/desktop/src/hooks/useCurrentDatabase.ts b/apps/desktop/src/hooks/useCurrentDatabase.ts new file mode 100644 index 000000000..d3122b1b3 --- /dev/null +++ b/apps/desktop/src/hooks/useCurrentDatabase.ts @@ -0,0 +1,11 @@ +import { atom, useAtom } from 'jotai' +import { IDatabaseNode } from '@penx/model-types' + +export const currentDatabaseAtom = atom( + null as any as IDatabaseNode, +) + +export function useCurrentDatabase() { + const [database, setDatabase] = useAtom(currentDatabaseAtom) + return { database, setDatabase } +} diff --git a/apps/desktop/src/hooks/useHandleSelect.ts b/apps/desktop/src/hooks/useHandleSelect.ts index 0fe41e5c9..d9e4d9433 100644 --- a/apps/desktop/src/hooks/useHandleSelect.ts +++ b/apps/desktop/src/hooks/useHandleSelect.ts @@ -9,12 +9,14 @@ import { useCommandAppLoading } from './useCommandAppLoading' import { useCommandAppUI } from './useCommandAppUI' import { useCommandPosition } from './useCommandPosition' import { useCurrentCommand } from './useCurrentCommand' +import { useCurrentDatabase } from './useCurrentDatabase' import { useSearch } from './useSearch' export function useHandleSelect() { const { setUI } = useCommandAppUI() const { setPosition } = useCommandPosition() const { setCurrentCommand } = useCurrentCommand() + const { setDatabase } = useCurrentDatabase() const { setLoading } = useCommandAppLoading() const { setSearch } = useSearch() @@ -26,6 +28,12 @@ export function useHandleSelect() { setPosition('COMMAND_APP') + if (item.data?.type === 'Database') { + setDatabase(item.data.database) + setUI({ type: 'database' }) + return + } + const ext = await db.getExtensionBySlug(item.data.extensionSlug) if (!ext) return @@ -134,7 +142,7 @@ export function useHandleSelect() { } if ( - ['marketplace', 'today', 'database', 'clipboard-history'].includes( + ['marketplace', 'today', 'clipboard-history'].includes( event.data?.type, ) ) { diff --git a/apps/desktop/src/hooks/useItems.ts b/apps/desktop/src/hooks/useItems.ts index 1489768a3..4a5112d1d 100644 --- a/apps/desktop/src/hooks/useItems.ts +++ b/apps/desktop/src/hooks/useItems.ts @@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query' import { atom, useAtom, useSetAtom } from 'jotai' import { IListItem } from 'penx' import { db } from '@penx/local-db' +import { Node } from '@penx/model' import { useSearch } from './useSearch' export const itemsAtom = atom([]) @@ -39,9 +40,12 @@ export function useCommands() { export function useLoadCommands() { return useQuery(['commands'], async () => { - const extensions = await db.listExtensions() + const [extensions, databases] = await Promise.all([ + db.listExtensions(), + db.listDatabases(), + ]) - return extensions.reduce((acc, cur) => { + const commands = extensions.reduce((acc, cur) => { return [ ...acc, ...cur.commands.map((item) => { @@ -61,6 +65,7 @@ export function useLoadCommands() { subtitle: cur.name, icon: getIcon(), data: { + type: 'Command', assets: cur.assets, filters: item.filters, runtime: item.runtime, @@ -73,6 +78,29 @@ export function useLoadCommands() { }), ] }, [] as IListItem[]) + + const databaseItems = databases.reduce((acc, item) => { + const node = new Node(item) + if (node.isSpecialDatabase) return acc + return [ + ...acc, + { + type: 'command', + title: node.tagName, + subtitle: '', + icon: { + value: '#', + bg: node.tagColor, + }, + data: { + type: 'Database', + database: item, + }, + } as IListItem, + ] + }, [] as IListItem[]) + + return [...commands, ...databaseItems] }) } diff --git a/packages/app/src/Workbench/PanelItem.tsx b/packages/app/src/Workbench/PanelItem.tsx index c09666c9e..a46aa43e1 100644 --- a/packages/app/src/Workbench/PanelItem.tsx +++ b/packages/app/src/Workbench/PanelItem.tsx @@ -87,8 +87,6 @@ export function PanelItem({ node, index }: Props) { const plugins = [withBulletPlugin] - const { isOpen, setIsOpen } = useQuickAdd() - if (!activeSpace.isOutliner) { plugins.push(withAutoNodeId) } diff --git a/packages/app/src/Workbench/Settings/AccountSettings/AccountSettings.tsx b/packages/app/src/Workbench/Settings/AccountSettings/AccountSettings.tsx index 5e302e4ac..bedec24d3 100644 --- a/packages/app/src/Workbench/Settings/AccountSettings/AccountSettings.tsx +++ b/packages/app/src/Workbench/Settings/AccountSettings/AccountSettings.tsx @@ -16,7 +16,7 @@ export function AccountSettings() { {data.userId} diff --git a/packages/app/src/Workbench/Sidebar/Sidebar.tsx b/packages/app/src/Workbench/Sidebar/Sidebar.tsx index 3a0c8c30e..a5771872c 100644 --- a/packages/app/src/Workbench/Sidebar/Sidebar.tsx +++ b/packages/app/src/Workbench/Sidebar/Sidebar.tsx @@ -152,7 +152,7 @@ export const Sidebar = memo( }} /> - { store.router.routeTo('MARKETPLACE') }} - /> + /> */} {/* { - {!isBackedUp && session && name === 'NODE' && } + {/* {!isBackedUp && session && name === 'NODE' && } */} = memo( function SingleSelectCell(props) { const { cell } = props - const { options, deleteCellOption } = useDatabaseContext() + const { options = [], deleteCellOption } = useDatabaseContext() const [value, setValue] = useState( Array.isArray(cell.props.data) ? cell.props.data : [], ) diff --git a/packages/local-db/src/libs/getRandomColor.ts b/packages/local-db/src/libs/getRandomColor.ts index d79bc7feb..b16f9eff7 100644 --- a/packages/local-db/src/libs/getRandomColor.ts +++ b/packages/local-db/src/libs/getRandomColor.ts @@ -12,7 +12,7 @@ export function getColorNames(postfix = '500') { } export function getRandomColor(postfix = '500'): string { - const keys = getColorNames() + const keys = getColorNames(postfix) const index = Math.floor(Math.random() * keys.length) return keys[index]! diff --git a/packages/model/src/Node.ts b/packages/model/src/Node.ts index b0aa9f939..47fc73c77 100644 --- a/packages/model/src/Node.ts +++ b/packages/model/src/Node.ts @@ -226,6 +226,12 @@ export class Node { return today === this.date } + get isSpecialDatabase() { + if (this.tagName === '__FILE__' || this.tagName === '__TODO__') return true + if (this.tagName.startsWith('$template__')) return true + return false + } + get fileHash() { const element = this.element as any try { diff --git a/packages/penx/src/components/ListBuilder.ts b/packages/penx/src/components/ListBuilder.ts index 4dbe572e4..061243f4d 100644 --- a/packages/penx/src/components/ListBuilder.ts +++ b/packages/penx/src/components/ListBuilder.ts @@ -26,6 +26,13 @@ export interface ListHeading { title: string } +export interface ObjectIcon { + value: ImageLike | undefined | null + tooltip?: string + color?: string + bg?: string +} + export interface IListItem { id?: string @@ -45,12 +52,7 @@ export interface IListItem { tooltip?: string | null } - icon?: - | ImageLike - | { - value: ImageLike | undefined | null - tooltip: string - } + icon?: ImageLike | ObjectIcon actions?: ListItemAction[] @@ -78,6 +80,10 @@ export function isListJSON(json: any): json is ListJSON { return json.type === 'list' } +export function isObjectIcon(icon: any): icon is ObjectIcon { + return typeof icon === 'object' && icon?.value !== undefined +} + export class ListBuilder { isShowingDetail = false isLoading = false diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 105ee7ab6..c4a3be463 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -812,6 +812,9 @@ importers: '@penx/app': specifier: workspace:* version: link:../../packages/app + '@penx/cell-fields': + specifier: workspace:* + version: link:../../packages/cell-fields '@penx/cmdk': specifier: workspace:* version: link:../../packages/cmdk @@ -21842,6 +21845,7 @@ packages: rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@2.7.1: