Add a modal dialog to initialize a new Git repository, replacing the previous prompt-based flow. It integrates with the app state and invokes the initialization operation then opens the repository on confirmation. Also adds styles, keyboard handling, accessibility hints, a folder browser, initial-branch input, and German/English labels with busy state. - New dialog component with folder picker, branch input, and i18n. - Wire dialog open/close and confirm handler to init and open actions. - Add CSS rules for dialog layout, controls, and error/busy states.
150 lines
5.4 KiB
Svelte
150 lines
5.4 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from "svelte";
|
|
import { open as openDialog } from "@tauri-apps/plugin-dialog";
|
|
import { Folder, FolderOpen, GitBranch, LoaderCircle, Plus, X } from "@lucide/svelte";
|
|
import type { AppLanguage } from "../types";
|
|
|
|
interface Props {
|
|
isBusy: boolean;
|
|
language: AppLanguage;
|
|
onInit: (path: string, branch: string) => void;
|
|
onClose: () => void;
|
|
}
|
|
|
|
let {
|
|
isBusy = false,
|
|
language = "en",
|
|
onInit = () => {},
|
|
onClose = () => {},
|
|
}: Props = $props();
|
|
|
|
let path = $state("");
|
|
let branch = $state("main");
|
|
let browseError = $state("");
|
|
const isGerman = $derived(language === "de");
|
|
const pathPlaceholder = navigator.userAgent.includes("Windows")
|
|
? "C:\\Projects\\my-repository"
|
|
: "/home/user/projects/my-repository";
|
|
|
|
function submit(event: SubmitEvent) {
|
|
event.preventDefault();
|
|
const targetPath = path.trim();
|
|
const branchName = branch.trim();
|
|
if (!targetPath || !branchName || isBusy) return;
|
|
onInit(targetPath, branchName);
|
|
}
|
|
|
|
function handleKeydown(event: KeyboardEvent) {
|
|
if (event.key === "Escape" && !isBusy) onClose();
|
|
}
|
|
|
|
async function chooseFolder() {
|
|
if (isBusy) return;
|
|
browseError = "";
|
|
try {
|
|
const selected = await openDialog({
|
|
title: isGerman ? "Ordner für das neue Repository auswählen" : "Select folder for the new repository",
|
|
directory: true,
|
|
multiple: false,
|
|
defaultPath: path.trim() || undefined,
|
|
});
|
|
if (typeof selected === "string") path = selected;
|
|
} catch (error) {
|
|
browseError = error instanceof Error ? error.message : String(error);
|
|
}
|
|
}
|
|
|
|
onMount(() => {
|
|
window.addEventListener("keydown", handleKeydown);
|
|
return () => window.removeEventListener("keydown", handleKeydown);
|
|
});
|
|
</script>
|
|
|
|
<div class="dialog-backdrop app-chrome-backdrop" role="presentation">
|
|
<div
|
|
class="dialog init-repository-dialog"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-labelledby="init-repository-title"
|
|
tabindex="-1"
|
|
>
|
|
<header class="dialog-header init-repository-header">
|
|
<div class="init-repository-heading">
|
|
<span class="init-repository-icon" aria-hidden="true"><Plus size={18} /></span>
|
|
<div>
|
|
<span class="eyebrow">{isGerman ? "Neues Repository" : "New repository"}</span>
|
|
<h2 id="init-repository-title">{isGerman ? "Repository initialisieren" : "Initialize repository"}</h2>
|
|
</div>
|
|
</div>
|
|
<button class="dialog-close" type="button" onclick={onClose} disabled={isBusy} title={isGerman ? "Schließen" : "Close"}>
|
|
<X size={18} aria-hidden="true" />
|
|
</button>
|
|
</header>
|
|
|
|
<form class="init-repository-form" onsubmit={submit}>
|
|
<p class="init-repository-description">
|
|
{isGerman
|
|
? "GitLite richtet in diesem Ordner ein neues Git-Repository ein. Vorhandene Dateien bleiben unverändert."
|
|
: "GitLite will create a new Git repository in this folder. Existing files will remain unchanged."}
|
|
</p>
|
|
|
|
<label class="new-branch-field init-repository-field init-repository-path-field">
|
|
<span>{isGerman ? "Zielordner" : "Repository folder"}</span>
|
|
<div class="init-repository-path-control">
|
|
<Folder size={16} aria-hidden="true" />
|
|
<!-- svelte-ignore a11y_autofocus -->
|
|
<input
|
|
bind:value={path}
|
|
autocomplete="off"
|
|
spellcheck="false"
|
|
placeholder={pathPlaceholder}
|
|
disabled={isBusy}
|
|
autofocus
|
|
aria-describedby="init-repository-path-hint"
|
|
/>
|
|
<button class="btn-secondary init-repository-browse" type="button" onclick={chooseFolder} disabled={isBusy}>
|
|
<FolderOpen size={15} aria-hidden="true" />
|
|
{isGerman ? "Auswählen…" : "Browse…"}
|
|
</button>
|
|
</div>
|
|
<small id="init-repository-path-hint">
|
|
{isGerman ? "Der Ordner wird angelegt, falls er noch nicht existiert." : "The folder will be created if it does not exist."}
|
|
</small>
|
|
{#if browseError}<small class="init-repository-error" role="alert">{browseError}</small>{/if}
|
|
</label>
|
|
|
|
<label class="new-branch-field init-repository-field">
|
|
<span>{isGerman ? "Name des ersten Branches" : "Initial branch name"}</span>
|
|
<div>
|
|
<GitBranch size={16} aria-hidden="true" />
|
|
<input
|
|
bind:value={branch}
|
|
autocomplete="off"
|
|
spellcheck="false"
|
|
placeholder="main"
|
|
disabled={isBusy}
|
|
aria-describedby="init-repository-branch-hint"
|
|
/>
|
|
</div>
|
|
<small id="init-repository-branch-hint">
|
|
{isGerman ? "Du kannst den Branch später jederzeit umbenennen." : "You can rename the branch at any time."}
|
|
</small>
|
|
</label>
|
|
|
|
<div class="new-branch-actions init-repository-actions">
|
|
<button class="btn-secondary" type="button" onclick={onClose} disabled={isBusy}>
|
|
{isGerman ? "Abbrechen" : "Cancel"}
|
|
</button>
|
|
<button class="btn-primary" type="submit" disabled={isBusy || path.trim().length === 0 || branch.trim().length === 0}>
|
|
{#if isBusy}
|
|
<LoaderCircle class="spin" size={16} aria-hidden="true" />
|
|
{:else}
|
|
<Plus size={16} aria-hidden="true" />
|
|
{/if}
|
|
{isGerman ? "Repository erstellen" : "Create repository"}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|