app tiles

This commit is contained in:
Chris Wanstrath 2026-02-25 20:33:02 -08:00
parent 363a82a845
commit 1a71656508
4 changed files with 93 additions and 71 deletions

View File

@ -63,7 +63,7 @@ export function DashboardLanding({ render }: { render: () => void }) {
</TabBar>
<TabContent active={dashboardTab === 'urls' || undefined}>
<Urls />
<Urls render={render} />
</TabContent>
<TabContent active={dashboardTab === 'logs' || undefined}>

View File

@ -1,16 +1,16 @@
import { buildAppUrl } from '../../shared/urls'
import { apps } from '../state'
import { apps, setSelectedApp } from '../state'
import {
EmptyState,
StatusDot,
UrlLeft,
UrlLink,
UrlList,
UrlPort,
UrlRow,
Tile,
TileGrid,
TileIcon,
TileName,
TilePort,
TileStatus,
} from '../styles'
export function Urls() {
export function Urls({ render }: { render: () => void }) {
const nonTools = apps.filter(a => !a.tool)
if (nonTools.length === 0) {
@ -18,26 +18,32 @@ export function Urls() {
}
return (
<UrlList>
<TileGrid>
{nonTools.map(app => {
const url = buildAppUrl(app.name, location.origin)
const running = app.state === 'running'
const openAppPage = (e: MouseEvent) => {
e.preventDefault()
e.stopPropagation()
setSelectedApp(app.name)
render()
}
return (
<UrlRow key={app.name}>
<UrlLeft>
<StatusDot state={app.state} />
<span>{app.icon}</span>
{running ? (
<UrlLink href={url} target="_blank">{url}</UrlLink>
) : (
<span style={{ color: 'var(--colors-textFaint)' }}>{app.name}</span>
)}
</UrlLeft>
{app.port ? <UrlPort>:{app.port}</UrlPort> : null}
</UrlRow>
<Tile
key={app.name}
href={running ? url : undefined}
target={running ? '_blank' : undefined}
style={running ? undefined : { cursor: 'default' }}
>
<TileStatus state={app.state} onClick={openAppPage} />
<TileIcon>{app.icon}</TileIcon>
<TileName>{app.name}</TileName>
<TilePort>{app.port ? `:${app.port}` : '\u2014'}</TilePort>
</Tile>
)
})}
</UrlList>
</TileGrid>
)
}

View File

@ -203,58 +203,73 @@ export const LogStatus = define('LogStatus', {
},
})
// URL List
export const UrlLeft = define('UrlLeft', {
display: 'flex',
alignItems: 'center',
gap: 8,
minWidth: 0,
})
export const UrlLink = define('UrlLink', {
base: 'a',
color: theme('colors-link'),
textDecoration: 'none',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
selectors: {
'&:hover': { textDecoration: 'underline' },
},
})
export const UrlList = define('UrlList', {
// App Tiles Grid
export const TileGrid = define('TileGrid', {
width: '100%',
minWidth: 400,
maxWidth: 800,
maxWidth: 900,
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))',
gap: 20,
})
export const Tile = define('Tile', {
base: 'a',
position: 'relative',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 8,
padding: '28px 20px 24px',
background: theme('colors-bgElement'),
border: `1px solid ${theme('colors-border')}`,
borderRadius: theme('radius-md'),
overflow: 'hidden',
})
export const UrlPort = define('UrlPort', {
fontFamily: theme('fonts-mono'),
fontSize: 12,
color: theme('colors-textFaint'),
flexShrink: 0,
})
export const UrlRow = define('UrlRow', {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '10px 16px',
fontFamily: theme('fonts-mono'),
fontSize: 13,
textDecoration: 'none',
cursor: 'pointer',
selectors: {
'&:hover': {
background: theme('colors-bgHover'),
},
'&:not(:last-child)': {
borderBottom: `1px solid ${theme('colors-border')}`,
borderColor: theme('colors-textFaint'),
},
},
})
export const TileIcon = define('TileIcon', {
fontSize: 48,
lineHeight: 1,
userSelect: 'none',
})
export const TileName = define('TileName', {
fontSize: 15,
fontWeight: 600,
color: theme('colors-text'),
textAlign: 'center',
})
export const TilePort = define('TilePort', {
fontFamily: theme('fonts-mono'),
fontSize: 13,
color: theme('colors-textFaint'),
})
export const TileStatus = define('TileStatus', {
position: 'absolute',
top: 8,
right: 8,
width: 2,
height: 2,
borderRadius: '50%',
cursor: 'pointer',
padding: 4,
backgroundClip: 'content-box',
variants: {
state: {
error: { background: theme('colors-statusInvalid') },
invalid: { background: theme('colors-statusInvalid') },
stopped: { background: theme('colors-statusStopped') },
starting: { background: theme('colors-statusStarting') },
running: { background: theme('colors-statusRunning') },
stopping: { background: theme('colors-statusStarting') },
},
},
})

View File

@ -15,11 +15,12 @@ export {
LogStatus,
LogText,
LogTimestamp,
UrlLeft,
UrlLink,
UrlList,
UrlPort,
UrlRow,
Tile,
TileGrid,
TileIcon,
TileName,
TilePort,
TileStatus,
VitalCard,
VitalLabel,
VitalsSection,