fix(app): new layout issues
This commit is contained in:
@@ -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: {
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user