fix(app): new layout issues

This commit is contained in:
Adam
2026-01-15 07:00:53 -06:00
parent 679270d9e0
commit 564d3edfac
4 changed files with 113 additions and 31 deletions

View File

@@ -47,13 +47,34 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
const globalSdk = useGlobalSDK() const globalSdk = useGlobalSDK()
const globalSync = useGlobalSync() const globalSync = useGlobalSync()
const server = useServer() const server = useServer()
const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value)
const migrate = (value: unknown) => {
if (!isRecord(value)) return value
const sidebar = value.sidebar
if (!isRecord(sidebar)) return value
if (typeof sidebar.workspaces !== "boolean") return value
return {
...value,
sidebar: {
...sidebar,
workspaces: {},
workspacesDefault: sidebar.workspaces,
},
}
}
const target = Persist.global("layout", ["layout.v6"])
const [store, setStore, _, ready] = persisted( const [store, setStore, _, ready] = persisted(
Persist.global("layout", ["layout.v6"]), { ...target, migrate },
createStore({ createStore({
sidebar: { sidebar: {
opened: false, opened: false,
width: 280, width: 280,
workspaces: false, workspaces: {} as Record<string, boolean>,
workspacesDefault: false,
}, },
terminal: { terminal: {
height: 280, height: 280,
@@ -305,12 +326,15 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
resize(width: number) { resize(width: number) {
setStore("sidebar", "width", width) setStore("sidebar", "width", width)
}, },
workspaces: createMemo(() => store.sidebar.workspaces ?? false), workspaces(directory: string) {
setWorkspaces(value: boolean) { return createMemo(() => store.sidebar.workspaces[directory] ?? store.sidebar.workspacesDefault ?? false)
setStore("sidebar", "workspaces", value)
}, },
toggleWorkspaces() { setWorkspaces(directory: string, value: boolean) {
setStore("sidebar", "workspaces", (x) => !x) setStore("sidebar", "workspaces", directory, value)
},
toggleWorkspaces(directory: string) {
const current = store.sidebar.workspaces[directory] ?? store.sidebar.workspacesDefault ?? false
setStore("sidebar", "workspaces", directory, !current)
}, },
}, },
terminal: { terminal: {

View File

@@ -271,6 +271,12 @@ export default function Layout(props: ParentProps) {
return layout.projects.list().find((p) => p.worktree === directory || p.sandboxes?.includes(directory)) return layout.projects.list().find((p) => p.worktree === directory || p.sandboxes?.includes(directory))
}) })
const workspaceSetting = createMemo(() => {
const project = currentProject()
if (!project) return false
return layout.sidebar.workspaces(project.worktree)()
})
createEffect(() => { createEffect(() => {
const project = currentProject() const project = currentProject()
if (!project) return if (!project) return
@@ -306,7 +312,16 @@ export default function Layout(props: ParentProps) {
return sessions.filter((s) => !s.parentID) return sessions.filter((s) => !s.parentID)
} }
const currentSessions = createMemo(() => projectSessions(currentProject())) const currentSessions = createMemo(() => {
const project = currentProject()
if (!project) return [] as Session[]
if (workspaceSetting()) return projectSessions(project)
const [projectStore] = globalSync.child(project.worktree)
return projectStore.session
.filter((session) => session.directory === projectStore.path.directory)
.filter((session) => !session.parentID)
.toSorted(sortSessions)
})
type PrefetchQueue = { type PrefetchQueue = {
inflight: Set<string> inflight: Set<string>
@@ -729,6 +744,21 @@ export default function Layout(props: ParentProps) {
requestAnimationFrame(() => scrollToSession(id)) requestAnimationFrame(() => scrollToSession(id))
}) })
createEffect(() => {
const project = currentProject()
if (!project) return
if (workspaceSetting()) {
const dirs = [project.worktree, ...(project.sandboxes ?? [])]
for (const directory of dirs) {
globalSync.project.loadSessions(directory)
}
return
}
globalSync.project.loadSessions(project.worktree)
})
createEffect(() => { createEffect(() => {
if (isLargeViewport()) { if (isLargeViewport()) {
const sidebarWidth = layout.sidebar.opened() ? layout.sidebar.width() : 64 const sidebarWidth = layout.sidebar.opened() ? layout.sidebar.width() : 64
@@ -943,6 +973,7 @@ export default function Layout(props: ParentProps) {
}) })
const workspaces = createMemo(() => workspaceIds(props.project).slice(0, 2)) const workspaces = createMemo(() => workspaceIds(props.project).slice(0, 2))
const workspaceEnabled = createMemo(() => layout.sidebar.workspaces(props.project.worktree)())
const label = (directory: string) => { const label = (directory: string) => {
const [data] = globalSync.child(directory) const [data] = globalSync.child(directory)
const kind = directory === props.project.worktree ? "local" : "sandbox" const kind = directory === props.project.worktree ? "local" : "sandbox"
@@ -959,6 +990,15 @@ export default function Layout(props: ParentProps) {
.slice(0, 2) .slice(0, 2)
} }
const projectSessions = () => {
const [data] = globalSync.child(props.project.worktree)
return data.session
.filter((session) => session.directory === data.path.directory)
.filter((session) => !session.parentID)
.toSorted(sortSessions)
.slice(0, 2)
}
const trigger = ( const trigger = (
<button <button
type="button" type="button"
@@ -980,23 +1020,39 @@ export default function Layout(props: ParentProps) {
<div class="-m-3 flex flex-col w-72"> <div class="-m-3 flex flex-col w-72">
<div class="px-3 py-2 text-12-medium text-text-strong">Recent sessions</div> <div class="px-3 py-2 text-12-medium text-text-strong">Recent sessions</div>
<div class="px-2 pb-2 flex flex-col gap-2"> <div class="px-2 pb-2 flex flex-col gap-2">
<For each={workspaces()}> <Show
{(directory) => ( when={workspaceEnabled()}
<div class="flex flex-col gap-1"> fallback={
<div class="px-2 py-0.5 flex items-center gap-1 min-w-0"> <For each={projectSessions()}>
<div class="shrink-0 size-6 flex items-center justify-center"> {(session) => (
<Icon name="branch" size="small" class="text-icon-base" /> <SessionItem
session={session}
slug={base64Encode(props.project.worktree)}
dense
mobile={props.mobile}
/>
)}
</For>
}
>
<For each={workspaces()}>
{(directory) => (
<div class="flex flex-col gap-1">
<div class="px-2 py-0.5 flex items-center gap-1 min-w-0">
<div class="shrink-0 size-6 flex items-center justify-center">
<Icon name="branch" size="small" class="text-icon-base" />
</div>
<span class="truncate text-14-medium text-text-strong">{label(directory)}</span>
</div> </div>
<span class="truncate text-14-medium text-text-strong">{label(directory)}</span> <For each={sessions(directory)}>
{(session) => (
<SessionItem session={session} slug={base64Encode(directory)} dense mobile={props.mobile} />
)}
</For>
</div> </div>
<For each={sessions(directory)}> )}
{(session) => ( </For>
<SessionItem session={session} slug={base64Encode(directory)} dense mobile={props.mobile} /> </Show>
)}
</For>
</div>
)}
</For>
</div> </div>
<div class="px-2 py-2 border-t border-border-weak-base"> <div class="px-2 py-2 border-t border-border-weak-base">
<Button <Button
@@ -1068,7 +1124,7 @@ export default function Layout(props: ParentProps) {
return `${kind} : ${name}` return `${kind} : ${name}`
}) })
const open = createMemo(() => store.workspaceExpanded[props.directory] ?? true) const open = createMemo(() => store.workspaceExpanded[props.directory] ?? true)
const hasMore = createMemo(() => local() && workspaceStore.session.length >= workspaceStore.limit) const hasMore = createMemo(() => local() && workspaceStore.sessionTotal > workspaceStore.session.length)
const loadMore = async () => { const loadMore = async () => {
if (!local()) return if (!local()) return
setWorkspaceStore("limit", (limit) => limit + 5) setWorkspaceStore("limit", (limit) => limit + 5)
@@ -1157,7 +1213,7 @@ export default function Layout(props: ParentProps) {
.filter((session) => !session.parentID) .filter((session) => !session.parentID)
.toSorted(sortSessions), .toSorted(sortSessions),
) )
const hasMore = createMemo(() => workspaceStore.session.length >= workspaceStore.limit) const hasMore = createMemo(() => workspaceStore.sessionTotal > workspaceStore.session.length)
const loadMore = async () => { const loadMore = async () => {
setWorkspaceStore("limit", (limit) => limit + 5) setWorkspaceStore("limit", (limit) => limit + 5)
await globalSync.project.loadSessions(props.project.worktree) await globalSync.project.loadSessions(props.project.worktree)
@@ -1324,9 +1380,9 @@ export default function Layout(props: ParentProps) {
<DropdownMenu.ItemLabel>Close project</DropdownMenu.ItemLabel> <DropdownMenu.ItemLabel>Close project</DropdownMenu.ItemLabel>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item onSelect={() => layout.sidebar.toggleWorkspaces()}> <DropdownMenu.Item onSelect={() => layout.sidebar.toggleWorkspaces(p().worktree)}>
<DropdownMenu.ItemLabel> <DropdownMenu.ItemLabel>
{layout.sidebar.workspaces() ? "Disable workspaces" : "Enable workspaces"} {layout.sidebar.workspaces(p().worktree)() ? "Disable workspaces" : "Enable workspaces"}
</DropdownMenu.ItemLabel> </DropdownMenu.ItemLabel>
</DropdownMenu.Item> </DropdownMenu.Item>
</DropdownMenu.Content> </DropdownMenu.Content>
@@ -1336,7 +1392,7 @@ export default function Layout(props: ParentProps) {
</div> </div>
<Show <Show
when={layout.sidebar.workspaces()} when={layout.sidebar.workspaces(p().worktree)()}
fallback={ fallback={
<> <>
<div class="py-4 px-3"> <div class="py-4 px-3">

View File

@@ -293,6 +293,11 @@ pub fn run() {
"# "#
)); ));
#[cfg(target_os = "macos")]
let window_builder = window_builder
.title_bar_style(tauri::TitleBarStyle::Overlay)
.hidden_title(true);
let _window = window_builder.build().expect("Failed to create window"); let _window = window_builder.build().expect("Failed to create window");
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();

View File

@@ -319,9 +319,6 @@ render(() => {
return ( return (
<PlatformProvider value={platform}> <PlatformProvider value={platform}>
<AppBaseProviders> <AppBaseProviders>
{ostype() === "macos" && (
<div class="mx-px bg-background-base border-b border-border-weak-base h-8" data-tauri-drag-region />
)}
<ServerGate> <ServerGate>
{(data) => { {(data) => {
setServerPassword(data().password) setServerPassword(data().password)