Skip to content

Commit

Permalink
feat: support FormApp
Browse files Browse the repository at this point in the history
  • Loading branch information
0xzio committed Jun 30, 2024
1 parent d5faad0 commit 8440aaf
Show file tree
Hide file tree
Showing 56 changed files with 1,326 additions and 290 deletions.
6 changes: 4 additions & 2 deletions .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"plugins": ["@ianvs/prettier-plugin-sort-imports"],
"plugins": [
"@ianvs/prettier-plugin-sort-imports"
],
"importOrder": [
"^react",
"<BUILTIN_MODULES>",
Expand All @@ -14,4 +16,4 @@
"^~(.*)$",
"^[./]"
]
}
}
4 changes: 2 additions & 2 deletions apps/desktop/.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# VITE_API_URL=https://app.penx.io
VITE_API_URL=http://localhost:3000
VITE_API_URL=https://app.penx.io
# VITE_API_URL=http://localhost:3000

NEXT_PUBLIC_PLATFORM=DESKTOP

Expand Down
1 change: 1 addition & 0 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"add": "^2.0.6",
"clsx": "^2.1.0",
"cmdk": "^1.0.0",
"fomir": "^0.22.0",
"idb-keyval": "^6.2.1",
"jotai": "^2.6.0",
"ky": "^1.1.3",
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { appEmitter } from '@penx/event'
import { StoreProvider } from '@penx/store'
import { TrpcProvider } from '@penx/trpc-client'
import '@glideapps/glide-data-grid/dist/index.css'
import { Fomir } from 'fomir'
import { fixPathEnv } from 'tauri-plugin-shellx-api'
import { registerDefaultAppHotkey } from '@penx/app'
import { handleEscape } from './common/handleEscape'
Expand All @@ -18,9 +19,11 @@ import { useInitThemeMode } from './hooks/useInitThemeMode'
import { MainApp } from './MainApp'
import '~/styles/globals.css'
import '~/styles/command.scss'
import FomirUIkit from './fomir-uikit'
import { config } from './config'

initFower()
Fomir.use(FomirUIkit)

async function init() {
handleEscape()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { memo, useEffect } from 'react'
import isEqual from 'react-fast-compare'
import { Box } from '@fower/react'
import { IListItem, isListApp, isMarkdownJSON } from '@penxio/preset-ui'
import { isFormApp, isListApp, isMarkdownJSON } from '@penxio/preset-ui'
import { Spinner } from 'uikit'
import { Command } from '@penx/model'
import { store } from '@penx/store'
Expand All @@ -11,6 +11,7 @@ import { CommandAppUI } from '~/hooks/useCommandAppUI'
import { AboutApp } from './AboutApp'
import { ClipboardHistoryApp } from './ClipboardHistoryApp'
import { DatabaseApp } from './DatabaseApp/DatabaseApp'
import { FormApp } from './FormApp/FormApp'
import { GeneralSettings } from './GeneralSettings/GeneralSettings'
import { InstalledExtensionsApp } from './InstalledExtensionsApp/InstalledExtensionsApp'
import { ListApp } from './ListApp/ListApp'
Expand Down Expand Up @@ -68,13 +69,19 @@ export const CommandApp = memo(
if (ui.type === 'render') {
const component = ui.component as any

console.log('=======component:', component)

if (isMarkdownJSON(component)) {
return <Markdown content={component.content} />
}

if (isListApp(component)) {
return <ListApp component={component} />
}

if (isFormApp(component)) {
return <FormApp component={component} />
}
}

return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import {
IViewNode,
} from '@penx/model-types'
import { mappedByKey } from '@penx/shared'
import { ICommandItem } from '~/common/types'
import { useValue } from '~/hooks/useValue'
import { StyledCommandEmpty, StyledCommandGroup } from '../../CommandComponents'
import { ListItemUI } from '../../ListItemUI'
import { CommandItemUI } from '../../CommandItemUI'
import { RowForm } from './RowForm'

interface Props {
Expand Down Expand Up @@ -92,7 +91,7 @@ export function DatabaseDetail(props: Props) {
value: item.row.id,
} as any

return <ListItemUI key={index} index={index} showIcon={false} item={listItem} />
return <CommandItemUI key={index} index={index} showIcon={false} item={listItem} />
})}
</StyledCommandGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { memo } from 'react'
import { Box } from '@fower/react'
import { FormJSON } from '@penxio/preset-ui'
import { Form, useForm } from 'fomir'

interface FormAppProps {
component: FormJSON
}

export const FormApp = memo(function FormApp({ component }: FormAppProps) {
console.log('=========component:', component)

const form = useForm({
onSubmit(values) {
alert(JSON.stringify(values, null, 2))
console.log('values', values)
},
children: [
...component.fields,
// {
// label: 'First Name',
// name: 'firstName',
// component: 'Input',
// value: '',
// validators: {
// required: 'First Name is requiredFirst Name is required',
// },
// },
// {
// label: 'Last Name',
// name: 'lastName',
// component: 'Input',
// value: '',
// validators: {
// required: 'First Name is required',
// },
// },
],
})

return (
<Box py4>
<Form form={form} />
</Box>
)
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ReactNode, useMemo } from 'react'
import { Box } from '@fower/react'
import { IAccessory, isAccessoryObjectText } from '@penxio/preset-ui'
import { useCurrentCommand } from '~/hooks/useCurrentCommand'
import { ListItemIcon } from '../../ListItemIcon'

interface AccessoryProps {
item: IAccessory
}

export function Accessory({ item }: AccessoryProps) {
const { currentCommand } = useCurrentCommand()
const assets = currentCommand?.extension?.assets || {}

let text: ReactNode = useMemo(() => {
if (typeof item.text === 'string' || typeof item.text === 'number') {
return <Box>{item.text}</Box>
}
if (isAccessoryObjectText(item.text)) {
return <Box color={item.text.color || 'gray600'}>{item.text?.value || ''}</Box>
}
return null
}, [item.text])
let tag: ReactNode = item.tag ? (
<Box bgAmber500 white h-24 rounded px2 toCenterY>
{item.tag.value}
</Box>
) : null

let icon: ReactNode = item.icon ? <ListItemIcon roundedFull icon={assets[item.icon]} /> : null

return (
<Box toCenterY gap1>
{icon}
{text}
{tag}
</Box>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { workerStore } from '~/common/workerStore'
import { useSearch } from '~/hooks/useSearch'
import { useValue } from '~/hooks/useValue'
import { StyledCommandGroup } from '../../CommandComponents'
import { ListItemUI } from '../../ListItemUI'
import { Detail } from './Detail'
import { ListItem } from './domains/ListItem.domain'
import { ListItemUI } from './ListItemUI'

interface ListAppProps {
component: ListJSON
Expand All @@ -23,17 +24,20 @@ export const ListApp = memo(function ListApp({ component }: ListAppProps) {

const filteredItems = !filtering
? items
: items.filter((item) => {
return item.title.toString().toLowerCase().includes(search.toLowerCase())
: items.filter((item, index) => {
const listItem = new ListItem(item, index)
return listItem.title.toLowerCase().includes(search.toLowerCase())
})

useEffect(() => {
const find = component.items.find((item) => item.title === value)
if (!items.length) return
const find = items.find((_, index) => String(index) === value)

if (!find) {
const firstItem = component.items.find((item) => !item.type)
firstItem && setValue(firstItem.title as string)
const firstItem = new ListItem(items[0], 0)
firstItem && setValue(firstItem.value)
}
}, [component, value, setValue])
}, [items, value, setValue])

useEffect(() => {
if (value && isShowingDetail && items.length) {
Expand Down Expand Up @@ -61,17 +65,17 @@ export const ListApp = memo(function ListApp({ component }: ListAppProps) {
scrollPaddingBlockStart: 8,
}}
>
{filteredItems.sort().map((item, index) => {
{filteredItems.sort().map((raw, index) => {
const item = new ListItem(raw, index)
return (
<ListItemUI
// key={index}
key={item.title.toString()}
key={index}
index={index}
titleLayout={titleLayout}
item={item as any} // TODO: handle any
item={item}
onSelect={async () => {
if (item.actions?.[0]) {
const defaultAction = item.actions?.[0]
if (raw.actions?.[0]) {
const defaultAction = raw.actions?.[0]
if (defaultAction.type === 'OpenInBrowser') {
open(defaultAction.url)
const appWindow = getCurrent()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Box, FowerHTMLProps } from '@fower/react'
import { useCurrentCommand } from '~/hooks/useCurrentCommand'
import { StyledCommandItem } from '../../CommandComponents'
import { ListItemIcon } from '../../ListItemIcon'
import { Accessory } from './Accessory'
import { ListItem } from './domains/ListItem.domain'

interface ListItemUIProps extends Omit<FowerHTMLProps<'div'>, 'onSelect'> {
index: number
item: ListItem
titleLayout?: 'column' | 'row'
onSelect?: () => Promise<void>
}

export const ListItemUI = ({
item,
index,
titleLayout = 'row',
onSelect,
...rest
}: ListItemUIProps) => {
const { currentCommand } = useCurrentCommand()

// if (item.type === 'list-heading') {
// return (
// <Box textXS gray400 pl-10 mb-2 mt2={index > 0}>
// {title}
// </Box>
// )
// }

function select() {
if (onSelect) {
onSelect()
} else {
// TODO:...
// commandService.handleSelect()
}
}

return (
<StyledCommandItem
cursorPointer
toCenterY
toBetween
px2
py2
gap4
roundedLG
black
bgNeutral100--hover
value={item.value}
keywords={item.keywords}
onSelect={select}
onClick={select}
{...rest}
>
<Box toCenterY gap2>
<ListItemIcon icon={item.icon} />
<Box flexDirection={titleLayout} gapY1 toCenterY gapX2>
<Box text-14>{item.title}</Box>
<Box text-12 zinc400>
{item.subtitle}
</Box>
</Box>
</Box>
{item?.extra && (
<Box toCenterY gap2 textXS gray600>
{item.extra.map((extra, index) => (
<Accessory key={index} item={extra} />
))}
</Box>
)}
</StyledCommandItem>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { IListItem, isTooltipValue } from '@penxio/preset-ui'

export class ListItem {
constructor(
public raw: IListItem,
public index: number,
) {}

get title() {
if (isTooltipValue(this.raw.title)) {
return this.raw.title.value
}
if (typeof this.raw.title === 'string') {
return this.raw.title
}
return ''
}

get subtitle() {
if (isTooltipValue(this.raw.subtitle)) {
return this.raw.subtitle.value
}
if (typeof this.raw.subtitle === 'string') {
return this.raw.subtitle
}
return ''
}

get value() {
return this.index.toString()
}

get icon() {
return this.raw.icon
}

get keywords() {
return [this.title, this.subtitle]
}

get extra() {
return this.raw.extra
}
}
Loading

0 comments on commit 8440aaf

Please sign in to comment.