diff --git a/NozCli/Commands/MkdirCommand.cs b/NozCli/Commands/MkdirCommand.cs new file mode 100644 index 0000000..7215b1d --- /dev/null +++ b/NozCli/Commands/MkdirCommand.cs @@ -0,0 +1,80 @@ +using NozCli.Core.Security; +using NozCli.Repl; +using Spectre.Console; + +namespace NozCli.Commands; + +public class MkdirCommand : ICommand +{ + public string Name => "mkdir"; + public string Description => "Create a new folder (writes _index.md)"; + public string Usage => "mkdir "; + + public async Task ExecuteAsync(string[] args, ReplContext ctx, CancellationToken ct = default) + { + var folderArg = args.FirstOrDefault(); + if (folderArg is null) + { + AnsiConsole.MarkupLine("[red]Usage:[/] mkdir "); + return; + } + + // Resolve full folder path relative to current navigation + var folderPath = ResolveFolderPath(folderArg.TrimEnd('/'), ctx); + + if (!SlugGuard.IsValid(folderPath)) + { + AnsiConsole.MarkupLine("[red]Ungültiger Ordnername.[/] Nur Kleinbuchstaben, Ziffern und Bindestriche erlaubt."); + return; + } + + // Derive a readable title from the last segment + var lastSegment = folderPath.Split('/')[^1]; + var title = ToTitle(lastSegment); + + await AnsiConsole.Status().StartAsync($"Erstelle [cyan]{folderPath}[/]…", async _ => + await ctx.Api.PutFolderIndexAsync(folderPath, title, ct: ct)); + + // Navigate into the new folder + NavigateInto(folderPath, ctx); + + AnsiConsole.MarkupLine($"[green]✓[/] Ordner erstellt → {ctx.CurrentPath}"); + AnsiConsole.MarkupLine($"[dim]Erstelle deine erste Notiz mit [white]new [/][/]"); + } + + private static string ResolveFolderPath(string segment, ReplContext ctx) + { + // Already a full multi-segment path (user typed full slug) + if (segment.Contains('/')) return segment; + + if (ctx.CurrentTopic is null) + return segment; + + if (ctx.CurrentSubPath is null) + return $"{ctx.CurrentTopic}/{segment}"; + + return $"{ctx.CurrentTopic}/{ctx.CurrentSubPath}/{segment}"; + } + + private static void NavigateInto(string folderPath, ReplContext ctx) + { + var parts = folderPath.Split('/'); + if (parts.Length == 1) + { + ctx.CurrentTopic = parts[0]; + ctx.CurrentSubPath = null; + } + else + { + ctx.CurrentTopic = parts[0]; + ctx.CurrentSubPath = string.Join('/', parts[1..]); + } + } + + // "new-subfolder" → "New Subfolder" + private static string ToTitle(string slug) => + string.Join(' ', slug.Split('-').Select(Capitalize)); + + private static string Capitalize(string s) => + s.Length == 0 ? s : char.ToUpperInvariant(s[0]) + s[1..]; +}