Skip to content
Merged
12 changes: 9 additions & 3 deletions src/home/rail/HomeNavItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ interface Props {
icon: ReactElement;
label: string;
active?: boolean;
onClick?: () => void;
}

export function HomeNavItem({ icon, label, active = false }: Props) {
export function HomeNavItem({ icon, label, active = false, onClick }: Props) {
return (
<div className={`home-nav-item${active ? " home-nav-item--active" : ""}`}>
<button
type="button"
className={`home-nav-item${active ? " home-nav-item--active" : ""}`}
onClick={onClick}
disabled={!onClick}
>
{icon}
<span>{label}</span>
</div>
</button>
);
}
11 changes: 10 additions & 1 deletion src/projects/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export function renameProject(id: string, newName: string): void {
const project = useProjectStore.getState().projects.find((p) => p.id === id);
if (!project) throw new Error(`unknown project: ${id}`);
if (project.name === name) return;
const duplicate = useProjectStore
.getState()
.projects.some((p) => p.id !== id && p.name.toLowerCase() === name.toLowerCase());
if (duplicate) throw new Error(`Un projet avec le nom « ${name} » existe déjà.`);
useProjectStore.getState().upsert({ ...project, name });
}

Expand All @@ -64,7 +68,7 @@ async function createProjectImpl(input: {
const projectPath = joinChild(parentDir, name);
const exists = await invoke<boolean>("fs_path_exists", { path: projectPath });
if (exists) {
throw new Error(`Un dossier existe déjà à ${projectPath}.`);
throw new Error(`Un projet avec ce nom existe déjà dans ce dossier.`);
}
await invoke("fs_ensure_dir", { dirPath: projectPath });

Expand Down Expand Up @@ -191,5 +195,10 @@ async function openProjectImpl(id: string): Promise<void> {
}

useProjectStore.getState().setActive(id, { touch: true });
// Reset open tabs so stale paths from the previous project don't linger.
// The IDE hydration logic in `bootstrapIdeStore` handles restoring tabs
// from the persisted snapshot, but on a live switch the old tabs would
// survive until the next persistence round-trip.
useIdeStore.setState({ openFiles: [], activeFile: null });
useIdeStore.getState().setView("ide");
}
8 changes: 7 additions & 1 deletion src/projects/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ export async function bootstrapProjects(): Promise<void> {
useProjectStore.getState().hydrate(existing);
const activeId = existing.activeProjectId ?? existing.projects[0]?.id ?? null;
if (activeId && existing.projects.some((p) => p.id === activeId)) {
await openProject(activeId);
try {
await openProject(activeId);
} catch (err) {
// The project's folder may have been deleted externally while the
// app was closed. Fall through to the Home view instead of crashing.
console.warn("bootstrap: could not reopen last project, showing Home", err);
}
}
return;
}
Expand Down
2 changes: 2 additions & 0 deletions src/projects/diskAutoSave.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { invoke } from "@tauri-apps/api/core";

import { toast } from "../ide/shell/toastStore";
import { persistenceEvents } from "../vfs/persistence";
import type { VirtualFS } from "../vfs/VirtualFS";
import { useProjectStore } from "./projectStore";
Expand Down Expand Up @@ -66,6 +67,7 @@ export function attachDiskAutoSave(vfs: VirtualFS): AutoSaveHandle {
}
} catch (err) {
console.error("disk autosave job failed", relPath, err);
toast.error(`Impossible de sauvegarder ${relPath} sur le disque.`);
}
}
const paths = vfs.listFiles();
Expand Down
31 changes: 28 additions & 3 deletions src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,12 @@ button.brand {
color: var(--fg-0);
background: var(--bg-1);
}
.tab:focus-visible {
outline: none;
color: var(--fg-0);
background: var(--bg-1);
box-shadow: inset 0 -2px 0 var(--accent);
}
.tab--active {
color: var(--fg-0);
background: var(--bg-1);
Expand Down Expand Up @@ -1443,6 +1449,25 @@ button.brand {
color: var(--fg-1);
font-size: 13px;
position: relative;
width: 100%;
text-align: left;
cursor: default;
transition:
background 0.12s,
color 0.12s;
}
.home-nav-item:not([disabled]):hover {
background: var(--bg-2);
color: var(--fg-0);
}
.home-nav-item:focus-visible {
outline: none;
background: var(--bg-2);
color: var(--fg-0);
}
.home-nav-item[disabled] {
opacity: 0.5;
cursor: default;
}
.home-nav-item--active {
background: var(--bg-3);
Expand Down Expand Up @@ -1477,7 +1502,7 @@ button.brand {
align-items: center;
gap: 8px;
padding: 6px 0;
cursor: default;
cursor: pointer;
color: inherit;
}
.home-rail-link:hover {
Expand Down Expand Up @@ -1779,8 +1804,8 @@ button.brand {
text-align: left;
cursor: pointer;
position: relative;
animation: proj-in 220ms ease-out both;
animation-delay: min(calc(var(--proj-idx, 0) * 40ms), 240ms);
animation: proj-in 180ms ease-out both;
animation-delay: min(calc(var(--proj-idx, 0) * 25ms), 120ms);
transition:
background 0.12s,
border-color 0.12s,
Expand Down