mobile dashboard

This commit is contained in:
Chris Wanstrath 2026-02-15 17:22:52 -08:00
parent f085d78fc1
commit 9c0762c882
8 changed files with 62 additions and 11 deletions

View File

@ -16,7 +16,7 @@ export function Dashboard({ render }: { render: () => void }) {
{selected ? ( {selected ? (
<AppDetail app={selected} render={render} /> <AppDetail app={selected} render={render} />
) : ( ) : (
<DashboardLanding /> <DashboardLanding render={render} />
)} )}
<Modal /> <Modal />
</Layout> </Layout>

View File

@ -1,9 +1,10 @@
import { useEffect } from 'hono/jsx' import { useEffect } from 'hono/jsx'
import { apps, setSelectedApp } from '../state' import { openAppSelectorModal } from '../modals'
import { apps, isNarrow, setSelectedApp } from '../state'
import { import {
AppSelectorChevron,
DashboardContainer, DashboardContainer,
DashboardHeader, DashboardHeader,
DashboardSubtitle,
DashboardTitle, DashboardTitle,
StatusDot, StatusDot,
StatusDotLink, StatusDotLink,
@ -13,16 +14,25 @@ import { update } from '../update'
import { UnifiedLogs, initUnifiedLogs } from './UnifiedLogs' import { UnifiedLogs, initUnifiedLogs } from './UnifiedLogs'
import { Vitals, initVitals } from './Vitals' import { Vitals, initVitals } from './Vitals'
export function DashboardLanding() { export function DashboardLanding({ render }: { render: () => void }) {
useEffect(() => { useEffect(() => {
initUnifiedLogs() initUnifiedLogs()
initVitals() initVitals()
}, []) }, [])
const narrow = isNarrow || undefined
return ( return (
<DashboardContainer> <DashboardContainer narrow={narrow}>
<DashboardHeader> <DashboardHeader>
<DashboardTitle>🐾 Toes</DashboardTitle> <DashboardTitle narrow={narrow}>
🐾 Toes
{isNarrow && (
<AppSelectorChevron onClick={() => openAppSelectorModal(render)}>
</AppSelectorChevron>
)}
</DashboardTitle>
{/*<DashboardSubtitle>Your personal web appliance</DashboardSubtitle>*/} {/*<DashboardSubtitle>Your personal web appliance</DashboardSubtitle>*/}
</DashboardHeader> </DashboardHeader>

View File

@ -1,6 +1,7 @@
import { define } from '@because/forge' import { define } from '@because/forge'
import type { App, LogLine as LogLineType } from '../../shared/types' import type { App, LogLine as LogLineType } from '../../shared/types'
import { getLogDates, getLogsForDate } from '../api' import { getLogDates, getLogsForDate } from '../api'
import { isNarrow } from '../state'
import { LogLine, LogsContainer, LogsHeader, LogTime, Section, SectionTitle } from '../styles' import { LogLine, LogsContainer, LogsHeader, LogTime, Section, SectionTitle } from '../styles'
import { theme } from '../themes' import { theme } from '../themes'
import { update } from '../update' import { update } from '../update'
@ -228,7 +229,7 @@ export function LogsSection({ app }: { app: App }) {
</SmallSelect> </SmallSelect>
</LogsControls> </LogsControls>
</LogsHeader> </LogsHeader>
<LogsContainer id="logs-content"> <LogsContainer id="logs-content" narrow={isNarrow || undefined}>
<LogsContent /> <LogsContent />
</LogsContainer> </LogsContainer>
</Section> </Section>

View File

@ -1,3 +1,4 @@
import { isNarrow } from '../state'
import { import {
LogApp, LogApp,
LogEntry, LogEntry,
@ -59,10 +60,11 @@ function parseLogText(text: string): { method?: string, path?: string, status?:
function LogLineEntry({ log }: { log: UnifiedLogLine }) { function LogLineEntry({ log }: { log: UnifiedLogLine }) {
const parsed = parseLogText(log.text) const parsed = parseLogText(log.text)
const statusColor = getStatusColor(parsed.status) const statusColor = getStatusColor(parsed.status)
const narrow = isNarrow || undefined
return ( return (
<LogEntry> <LogEntry narrow={narrow}>
<LogTimestamp>{formatTime(log.time)}</LogTimestamp> <LogTimestamp narrow={narrow}>{formatTime(log.time)}</LogTimestamp>
<LogApp>{log.app}</LogApp> <LogApp narrow={narrow}>{log.app}</LogApp>
<LogText style={statusColor ? { color: statusColor } : undefined}> <LogText style={statusColor ? { color: statusColor } : undefined}>
{log.text} {log.text}
</LogText> </LogText>

View File

@ -1,3 +1,4 @@
import { isNarrow } from '../state'
import { import {
GaugeContainer, GaugeContainer,
GaugeSvg, GaugeSvg,
@ -158,7 +159,7 @@ export function initVitals() {
export function Vitals() { export function Vitals() {
return ( return (
<VitalsSection id="vitals"> <VitalsSection id="vitals" narrow={isNarrow || undefined}>
<VitalsContent /> <VitalsContent />
</VitalsSection> </VitalsSection>
) )

View File

@ -8,6 +8,11 @@ export const VitalsSection = define('VitalsSection', {
gap: 24, gap: 24,
width: '100%', width: '100%',
maxWidth: 800, maxWidth: 800,
variants: {
narrow: {
gridTemplateColumns: '1fr',
},
},
}) })
export const VitalCard = define('VitalCard', { export const VitalCard = define('VitalCard', {
@ -144,17 +149,32 @@ export const LogEntry = define('LogEntry', {
background: theme('colors-bgHover'), background: theme('colors-bgHover'),
}, },
}, },
variants: {
narrow: {
padding: '2px 8px',
},
},
}) })
export const LogTimestamp = define('LogTimestamp', { export const LogTimestamp = define('LogTimestamp', {
color: theme('colors-textFaint'), color: theme('colors-textFaint'),
flexShrink: 0, flexShrink: 0,
variants: {
narrow: {
display: 'none',
},
},
}) })
export const LogApp = define('LogApp', { export const LogApp = define('LogApp', {
color: theme('colors-textMuted'), color: theme('colors-textMuted'),
flexShrink: 0, flexShrink: 0,
minWidth: 80, minWidth: 80,
variants: {
narrow: {
minWidth: 50,
},
},
}) })
export const LogText = define('LogText', { export const LogText = define('LogText', {

View File

@ -205,6 +205,13 @@ export const DashboardContainer = define('DashboardContainer', {
padding: 40, padding: 40,
paddingTop: 0, paddingTop: 0,
gap: 40, gap: 40,
variants: {
narrow: {
padding: 20,
paddingTop: 0,
gap: 24,
},
},
}) })
export const DashboardHeader = define('DashboardHeader', { export const DashboardHeader = define('DashboardHeader', {
@ -215,6 +222,11 @@ export const DashboardTitle = define('DashboardTitle', {
fontSize: 48, fontSize: 48,
fontWeight: 'bold', fontWeight: 'bold',
margin: 0, margin: 0,
variants: {
narrow: {
fontSize: 32,
},
},
}) })
export const DashboardSubtitle = define('DashboardSubtitle', { export const DashboardSubtitle = define('DashboardSubtitle', {

View File

@ -10,6 +10,11 @@ export const LogsContainer = define('LogsContainer', {
color: theme('colors-textMuted'), color: theme('colors-textMuted'),
maxHeight: 200, maxHeight: 200,
overflow: 'auto', overflow: 'auto',
variants: {
narrow: {
padding: 8,
},
},
render({ props: { children, id }, parts: { Root } }) { render({ props: { children, id }, parts: { Root } }) {
return <Root id={id} ref={(el: HTMLElement | null) => { return <Root id={id} ref={(el: HTMLElement | null) => {