web: scope sidebar to workspace routes

This commit is contained in:
2026-07-23 19:12:50 +09:00
parent 61b1735292
commit 2bd69f9403
6 changed files with 89 additions and 60 deletions
+4 -16
View File
@@ -1,26 +1,14 @@
<script lang="ts">
import { page } from '$app/state';
import WorkspaceAlerts from '$lib/workspace/alerts/WorkspaceAlerts.svelte';
import WorkspaceSidebar from '$lib/workspace/sidebar/WorkspaceSidebar.svelte';
import '../app.css';
import type { LayoutProps } from './$types';
let { data, children }: LayoutProps = $props();
let sidebarCollapsed = $state(false);
let { children }: LayoutProps = $props();
</script>
<WorkspaceAlerts />
<div class:sidebar-collapsed={sidebarCollapsed} class="workspace-layout">
<WorkspaceSidebar
workspace={data.workspace}
workspaceError={data.workspaceError}
repositories={data.repositories}
repositoriesError={data.repositoriesError}
currentPath={page.url.pathname}
collapsed={sidebarCollapsed}
onToggleCollapsed={() => (sidebarCollapsed = !sidebarCollapsed)}
/>
<div class="app-layout">
<header class="workspace-topbar">
<nav class="workspace-topbar-actions" aria-label="Global navigation">
<a class="topbar-icon-button" href="/account" aria-label="Open Account" title="Account">
@@ -31,7 +19,7 @@
</a>
</nav>
</header>
<main class="shell">
<div class="app-shell">
{@render children()}
</main>
</div>
</div>
+14 -38
View File
@@ -1,49 +1,25 @@
import { redirect } from "@sveltejs/kit";
import { loadJson, workspaceApiPath, workspaceRoute } from "$lib/workspace/api/http";
import type { RepositoryListResponse, WorkspaceResponse } from "$lib/workspace/sidebar/types";
import { loadJson, workspaceRoute } from "$lib/workspace/api/http";
import type { WorkspaceResponse } from "$lib/workspace/sidebar/types";
import type { LayoutLoad } from "./$types";
export const ssr = false;
export const prerender = false;
export const load: LayoutLoad = async ({ fetch, params, url }) => {
const workspaceId = params.workspaceId;
if (!workspaceId) {
const publicRoutes = new Set(["/account", "/login/device"]);
if (publicRoutes.has(url.pathname)) {
return {
workspace: null,
workspaceError: null,
repositories: null,
repositoriesError: null,
};
}
const workspace = await loadJson<WorkspaceResponse>(fetch, "/api/workspace");
if (workspace.data) {
const scopedPath = workspaceRoute(workspace.data.workspace_id);
throw redirect(307, `${scopedPath}${url.search}`);
}
return {
workspace: null,
workspaceError: workspace.error,
repositories: null,
repositoriesError: null,
};
if (params.workspaceId) {
return {};
}
const apiPath = (path: string) => workspaceApiPath(workspaceId, path);
const publicRoutes = new Set(["/account", "/login/device"]);
if (publicRoutes.has(url.pathname)) {
return {};
}
const [workspace, repositories] = await Promise.all([
loadJson<WorkspaceResponse>(fetch, apiPath("/workspace")),
loadJson<RepositoryListResponse>(fetch, apiPath("/repositories")),
]);
return {
workspace: workspace.data,
workspaceError: workspace.error,
repositories: repositories.data,
repositoriesError: repositories.error,
};
const workspace = await loadJson<WorkspaceResponse>(fetch, "/api/workspace");
if (workspace.data) {
const scopedPath = workspaceRoute(workspace.data.workspace_id);
throw redirect(307, `${scopedPath}${url.search}`);
}
return {};
};
@@ -0,0 +1,23 @@
<script lang="ts">
import { page } from '$app/state';
import WorkspaceSidebar from '$lib/workspace/sidebar/WorkspaceSidebar.svelte';
import type { LayoutProps } from './$types';
let { data, children }: LayoutProps = $props();
let sidebarCollapsed = $state(false);
</script>
<div class:sidebar-collapsed={sidebarCollapsed} class="workspace-layout">
<WorkspaceSidebar
workspace={data.workspace}
workspaceError={data.workspaceError}
repositories={data.repositories}
repositoriesError={data.repositoriesError}
currentPath={page.url.pathname}
collapsed={sidebarCollapsed}
onToggleCollapsed={() => (sidebarCollapsed = !sidebarCollapsed)}
/>
<main class="shell">
{@render children()}
</main>
</div>
@@ -0,0 +1,18 @@
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
import type { RepositoryListResponse, WorkspaceResponse } from "$lib/workspace/sidebar/types";
import type { LayoutLoad } from "./$types";
export const load: LayoutLoad = async ({ fetch, params }) => {
const apiPath = (path: string) => workspaceApiPath(params.workspaceId, path);
const [workspace, repositories] = await Promise.all([
loadJson<WorkspaceResponse>(fetch, apiPath("/workspace")),
loadJson<RepositoryListResponse>(fetch, apiPath("/repositories")),
]);
return {
workspace: workspace.data,
workspaceError: workspace.error,
repositories: repositories.data,
repositoriesError: repositories.error,
};
};