pick emoji

This commit is contained in:
Chris Wanstrath 2026-01-28 08:11:11 -08:00
parent a04d89d034
commit 9b84714623
3 changed files with 37 additions and 6 deletions

View File

@ -340,10 +340,14 @@ const toggleSidebar = () => {
const OpenEmojiPicker = define('OpenEmojiPicker', { const OpenEmojiPicker = define('OpenEmojiPicker', {
cursor: 'pointer', cursor: 'pointer',
render({ props, parts: { Root } }) { render({ props: { app, children }, parts: { Root } }) {
return <Root onClick={() => openEmojiPicker((emoji) => { return <Root onClick={() => openEmojiPicker((emoji) => {
console.log('Selected:', emoji) if (!app) return
})}>{props.children}</Root>
fetch(`/api/apps/${app.name}/icon?icon=${emoji}`, { method: 'POST' })
app.icon = emoji
render()
})}>{children}</Root>
} }
}) })
@ -351,7 +355,7 @@ const AppDetail = ({ app }: { app: App }) => (
<> <>
<MainHeader> <MainHeader>
<MainTitle> <MainTitle>
<OpenEmojiPicker>{app.icon ?? <StatusDot state={app.state} />}</OpenEmojiPicker> <OpenEmojiPicker app={app}>{app.icon ?? <StatusDot state={app.state} />}</OpenEmojiPicker>
&nbsp; &nbsp;
{app.name} {app.name}
</MainTitle> </MainTitle>

View File

@ -1,5 +1,5 @@
import type { Subprocess } from 'bun' import type { Subprocess } from 'bun'
import { existsSync, readdirSync, readFileSync, watch } from 'fs' import { existsSync, readdirSync, readFileSync, writeFileSync, watch } from 'fs'
import { join } from 'path' import { join } from 'path'
import type { App as SharedApp, AppState, LogLine } from '../shared/types' import type { App as SharedApp, AppState, LogLine } from '../shared/types'
@ -91,6 +91,20 @@ const loadApp = (dir: string): LoadResult => {
} }
} }
const saveApp = (dir: string, pkg: any) => {
const path = join(APPS_DIR, dir, 'package.json')
writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n')
}
export const updateAppIcon = (dir: string, icon: string) => {
const { pkg, error } = loadApp(dir)
if (error) throw new Error(error)
pkg.toes ??= {}
pkg.toes.icon = icon
saveApp(dir, pkg)
}
const isApp = (dir: string): boolean => const isApp = (dir: string): boolean =>
!loadApp(dir).error !loadApp(dir).error

View File

@ -1,5 +1,5 @@
import { Hype } from 'hype' import { Hype } from 'hype'
import { allApps, initApps, onChange, startApp, stopApp } from './apps' import { allApps, initApps, onChange, startApp, stopApp, updateAppIcon } from './apps'
import type { App as SharedApp } from '../shared/types' import type { App as SharedApp } from '../shared/types'
const app = new Hype({ layout: false }) const app = new Hype({ layout: false })
@ -75,4 +75,17 @@ app.post('/api/apps/:app/stop', c => {
return c.json({ ok: true }) return c.json({ ok: true })
}) })
app.post('/api/apps/:app/icon', c => {
const appName = c.req.param('app')
const icon = c.req.query('icon') ?? ''
if (!icon) return c.json({ error: 'No icon query param provided' })
try {
updateAppIcon(appName, icon)
return c.json({ ok: true })
} catch (error) {
return c.json({ error })
}
})
export default app.defaults export default app.defaults