Compare commits

...

2 Commits

Author SHA1 Message Date
303d2dfc72 simpler init script for tools 2026-02-04 08:35:42 -08:00
d8769b2d9d fix app tabs 2026-02-04 08:35:38 -08:00
8 changed files with 25 additions and 17 deletions

View File

@ -1,6 +1,6 @@
import { Hype } from '@because/hype' import { Hype } from '@because/hype'
import { define, stylesToCSS } from '@because/forge' import { define, stylesToCSS } from '@because/forge'
import { baseStyles, initScript, theme } from '@because/toes/tools' import { baseStyles, ToolScript, theme } from '@because/toes/tools'
import { readdir, stat } from 'fs/promises' import { readdir, stat } from 'fs/promises'
import { readFileSync } from 'fs' import { readFileSync } from 'fs'
import { join, extname, basename } from 'path' import { join, extname, basename } from 'path'
@ -309,7 +309,7 @@ function Layout({ title, children, highlight, editable }: LayoutProps) {
</head> </head>
<body> <body>
<script dangerouslySetInnerHTML={{ __html: fileMemoryScript }} /> <script dangerouslySetInnerHTML={{ __html: fileMemoryScript }} />
<script dangerouslySetInnerHTML={{ __html: initScript }} /> <ToolScript />
<Container> <Container>
{children} {children}
</Container> </Container>

View File

@ -1,6 +1,6 @@
import { Hype } from '@because/hype' import { Hype } from '@because/hype'
import { define, stylesToCSS } from '@because/forge' import { define, stylesToCSS } from '@because/forge'
import { baseStyles, initScript, theme } from '@because/toes/tools' import { baseStyles, ToolScript, theme } from '@because/toes/tools'
import { discoverCronJobs } from './lib/discovery' import { discoverCronJobs } from './lib/discovery'
import { scheduleJob, stopJob } from './lib/scheduler' import { scheduleJob, stopJob } from './lib/scheduler'
import { executeJob } from './lib/executor' import { executeJob } from './lib/executor'
@ -183,7 +183,7 @@ function Layout({ title, children }: { title: string; children: Child }) {
<link rel="stylesheet" href="/styles.css" /> <link rel="stylesheet" href="/styles.css" />
</head> </head>
<body> <body>
<script dangerouslySetInnerHTML={{ __html: initScript }} /> <ToolScript />
<Container> <Container>
{children} {children}
</Container> </Container>

View File

@ -2,7 +2,7 @@ import { define } from '@because/forge'
import type { App } from '../../shared/types' import type { App } from '../../shared/types'
import { restartApp, startApp, stopApp } from '../api' import { restartApp, startApp, stopApp } from '../api'
import { openDeleteAppModal, openRenameAppModal } from '../modals' import { openDeleteAppModal, openRenameAppModal } from '../modals'
import { apps, selectedTab } from '../state' import { apps, getSelectedTab } from '../state'
import { import {
ActionBar, ActionBar,
Button, Button,
@ -44,6 +44,7 @@ const OpenEmojiPicker = define('OpenEmojiPicker', {
export function AppDetail({ app, render }: { app: App, render: () => void }) { export function AppDetail({ app, render }: { app: App, render: () => void }) {
// Find all tools // Find all tools
const tools = apps.filter(a => a.tool) const tools = apps.filter(a => a.tool)
const selectedTab = getSelectedTab(app.name)
return ( return (
<Main> <Main>

View File

@ -1,16 +1,18 @@
import type { App } from '../../shared/types' import type { App } from '../../shared/types'
import { apps, selectedApp, selectedTab, setSelectedTab } from '../state' import { apps, getSelectedTab, setSelectedTab } from '../state'
import { Tab, TabBar } from '../styles' import { Tab, TabBar } from '../styles'
import { resetToolIframe } from '../tool-iframes' import { resetToolIframe } from '../tool-iframes'
export function Nav({ app, render }: { app: App; render: () => void }) { export function Nav({ app, render }: { app: App; render: () => void }) {
const selectedTab = getSelectedTab(app.name)
const handleTabClick = (tab: string) => { const handleTabClick = (tab: string) => {
// If clicking already-selected tool tab, reset to home // If clicking already-selected tool tab, reset to home
if (tab === selectedTab && tab !== 'overview') { if (tab === selectedTab && tab !== 'overview') {
resetToolIframe(tab, selectedApp) resetToolIframe(tab, app.name)
return return
} }
setSelectedTab(tab) setSelectedTab(app.name, tab)
render() render()
} }

View File

@ -1,6 +1,6 @@
import { render as renderApp } from 'hono/jsx/dom' import { render as renderApp } from 'hono/jsx/dom'
import { Dashboard } from './components' import { Dashboard } from './components'
import { apps, selectedApp, selectedTab, setApps, setSelectedApp } from './state' import { apps, getSelectedTab, selectedApp, setApps, setSelectedApp } from './state'
import { initModal } from './components/modal' import { initModal } from './components/modal'
import { initToolIframes, updateToolIframes } from './tool-iframes' import { initToolIframes, updateToolIframes } from './tool-iframes'
import { initUpdate } from './update' import { initUpdate } from './update'
@ -10,7 +10,7 @@ const render = () => {
// Update tool iframes after DOM settles // Update tool iframes after DOM settles
requestAnimationFrame(() => { requestAnimationFrame(() => {
const tools = apps.filter(a => a.tool) const tools = apps.filter(a => a.tool)
updateToolIframes(selectedTab, tools, selectedApp) updateToolIframes(getSelectedTab(selectedApp), tools, selectedApp)
}) })
} }

View File

@ -9,7 +9,7 @@ export let sidebarSection: 'apps' | 'tools' = (localStorage.getItem('sidebarSect
export let apps: App[] = [] export let apps: App[] = []
// Tab state // Tab state
export let selectedTab: string = localStorage.getItem('selectedTab') || 'overview' export let appTabs: Record<string, string> = JSON.parse(localStorage.getItem('appTabs') || '{}')
// State setters // State setters
export function setSelectedApp(name: string | null) { export function setSelectedApp(name: string | null) {
@ -35,7 +35,11 @@ export function setApps(newApps: App[]) {
apps = newApps apps = newApps
} }
export function setSelectedTab(tab: string) { export const getSelectedTab = (appName: string | null) =>
selectedTab = tab appName ? appTabs[appName] || 'overview' : 'overview'
localStorage.setItem('selectedTab', tab)
export function setSelectedTab(appName: string | null, tab: string) {
if (!appName) return
appTabs[appName] = tab
localStorage.setItem('appTabs', JSON.stringify(appTabs))
} }

View File

@ -1,3 +1,2 @@
export { theme } from '../client/themes' export { theme } from '../client/themes'
export { baseStyles, initScript } from './scripts' export { baseStyles, ToolScript } from './scripts.tsx'
export { define, stylesToCSS } from '@because/forge'

View File

@ -1,6 +1,6 @@
import { theme } from '../client/themes' import { theme } from '../client/themes'
export const initScript = ` const initScript = `
(function() { (function() {
var theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; var theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
document.body.setAttribute('data-theme', theme); document.body.setAttribute('data-theme', theme);
@ -29,3 +29,5 @@ body {
margin: 0; margin: 0;
} }
` `
export const ToolScript = () => <script dangerouslySetInnerHTML={{ __html: initScript }} />