+ @* Mode chips β shown only when repos exist *@
+ @if (RepoManager.Repositories.Count > 0)
+ {
+
+ }
- @if (showOptions)
+ @* Repo mode: repo selector + worktree strategy *@
+ @if (mode == FormMode.Repo)
{
-
- @if (RepoManager.Repositories.Count > 0)
+ @if (RepoManager.Repositories.Count > 1)
+ {
+
+ }
+ else
+ {
+
π¦ @RepoManager.Repositories[0].Name
+ }
+
+
+
+
+
+
+
+
+ @if (wtMode == WtMode.Branch)
+ {
+
+ }
+ else if (wtMode == WtMode.PR)
+ {
+
+ }
+ else if (wtMode == WtMode.Existing)
+ {
+ var repoWts = RepoManager.Worktrees.Where(w => w.RepoId == selectedRepoId).ToList();
+ @if (repoWts.Count > 0)
{
-
-
- @if (selectedWorktreeBranch != null)
- {
-
- β @selectedWorktreeBranch
-
-
- }
- else
+
+
}
- @if (filterRepoId == null)
+ else
{
-
-
-
-
-
-
-
+
No existing worktrees β try β‘ Auto or β Branch
}
+ }
+
+ @if (!string.IsNullOrEmpty(worktreeError))
+ {
+
β @worktreeError
+ }
+ }
+ else if (mode == FormMode.Directory)
+ {
+
+
+
}
+
+
+
@@ -140,214 +117,197 @@ else
[Parameter] public string SelectedModel { get; set; } = "claude-opus-4.6";
[Parameter] public EventCallback
SelectedModelChanged { get; set; }
- [Parameter] public EventCallback<(string Name, string Model, string Directory, string? WorktreeId, string? InitialPrompt)> OnCreate { get; set; }
+ [Parameter] public EventCallback<(string Name, string Model, string Directory, string? WorktreeId, string? InitialPrompt, string? RepoId, string? BranchName, int? PrNumber)> OnCreate { get; set; }
[Parameter] public EventCallback OnBrowseDirectory { get; set; }
[Parameter] public string SessionName { get; set; } = "";
[Parameter] public EventCallback SessionNameChanged { get; set; }
- private bool isExpanded = false;
- private bool showOptions = false;
- private bool showWorktreePicker = false;
- private string? filterRepoId; // Filter worktree picker to a specific repo
+ private enum FormMode { Repo, Directory, Empty }
+ private enum WtMode { Auto, Branch, PR, Existing }
+
+ private bool isExpanded;
+ private FormMode mode;
+ private WtMode wtMode = WtMode.Auto;
+ private string? selectedRepoId;
+ private string? selectedWorktreeId;
+ private string branchInput = "";
+ private string prInput = "";
private string initialPrompt = "";
private string sessionDirectory = "";
- private string? selectedWorktreePath;
- private string? selectedWorktreeId;
- private string? selectedWorktreeBranch;
-
- private string? newWorktreeRepoId;
- private string newWorktreeBranch = "";
- private string newWorktreePr = "";
- private string newWorktreeMode = "branch";
private string? worktreeError;
private bool isCreatingWorktree;
+ private bool nameManuallyEdited;
private void Expand()
{
isExpanded = true;
- filterRepoId = null; // Clear any repo filter when manually expanding
+ nameManuallyEdited = false;
+ mode = RepoManager.Repositories.Count > 0 ? FormMode.Repo : FormMode.Empty;
+ if (RepoManager.Repositories.Count > 0)
+ selectedRepoId = RepoManager.Repositories[0].Id;
+ AutoSelectFirstWorktree();
}
+
public void ExpandForRepo(string repoId)
{
isExpanded = true;
- showOptions = true;
- worktreeError = null;
- filterRepoId = repoId; // Filter to this repo only
- showWorktreePicker = true;
- newWorktreeRepoId = null; // Clear any open form so the button shows
-
- // If worktrees exist for this repo, auto-select the first one but keep picker open
- var existingWorktrees = RepoManager.Worktrees.Where(w => w.RepoId == repoId).ToList();
- if (existingWorktrees.Count > 0)
- {
- var wt = existingWorktrees[0];
- sessionDirectory = wt.Path;
- selectedWorktreePath = wt.Path;
- selectedWorktreeId = wt.Id;
- selectedWorktreeBranch = wt.Branch;
- // Don't close the picker - we want to show the "+ New worktree..." button
- if (string.IsNullOrWhiteSpace(SessionName))
- {
- SessionName = wt.Branch;
- _ = SessionNameChanged.InvokeAsync(SessionName);
- }
- }
-
+ nameManuallyEdited = false;
+ mode = FormMode.Repo;
+ selectedRepoId = repoId;
+ wtMode = WtMode.Auto;
+ AutoSelectFirstWorktree();
StateHasChanged();
}
+
private void Collapse()
{
isExpanded = false;
- showOptions = false;
- showWorktreePicker = false;
- newWorktreeRepoId = null;
- filterRepoId = null; // Clear repo filter
+ worktreeError = null;
+ branchInput = "";
+ prInput = "";
+ sessionDirectory = "";
+ initialPrompt = "";
+ selectedWorktreeId = null;
+ nameManuallyEdited = false;
}
- private void SetWorktreeMode(string mode) => newWorktreeMode = mode;
- private void SetModeBranch() => newWorktreeMode = "branch";
- private void SetModePr() => newWorktreeMode = "pr";
+ private void SetMode(FormMode newMode)
+ {
+ mode = newMode;
+ worktreeError = null;
+ if (!nameManuallyEdited) { SessionName = ""; _ = SessionNameChanged.InvokeAsync(""); }
+ }
- private void ToggleWorktreePicker()
+ private void SetWtMode(WtMode newWtMode)
{
- showWorktreePicker = !showWorktreePicker;
- // When manually toggling picker, clear the filter to show all repos
- if (showWorktreePicker) filterRepoId = null;
+ wtMode = newWtMode;
+ worktreeError = null;
+ branchInput = "";
+ prInput = "";
+ if (newWtMode == WtMode.Existing)
+ AutoSelectFirstWorktree();
+ if (!nameManuallyEdited) UpdateAutoName();
}
- private async Task OnNameInput(ChangeEventArgs e)
+ private void OnRepoChanged(ChangeEventArgs e)
{
- SessionName = e.Value?.ToString() ?? "";
- await SessionNameChanged.InvokeAsync(SessionName);
+ selectedRepoId = e.Value?.ToString();
+ if (wtMode == WtMode.Existing) AutoSelectFirstWorktree();
+ if (!nameManuallyEdited) UpdateAutoName();
}
- private async Task OnModelSelected(string model)
+ private void OnExistingWtChanged(ChangeEventArgs e)
{
- SelectedModel = model;
- await SelectedModelChanged.InvokeAsync(model);
+ selectedWorktreeId = e.Value?.ToString();
+ if (!nameManuallyEdited) UpdateAutoName();
+ }
+
+ private void AutoSelectFirstWorktree()
+ {
+ if (selectedRepoId == null) return;
+ var first = RepoManager.Worktrees.FirstOrDefault(w => w.RepoId == selectedRepoId);
+ selectedWorktreeId = first?.Id;
}
- private void SelectWorktree(WorktreeInfo wt)
+ private void UpdateAutoName()
{
- sessionDirectory = wt.Path;
- selectedWorktreePath = wt.Path;
- selectedWorktreeId = wt.Id;
- selectedWorktreeBranch = wt.Branch;
- showWorktreePicker = false;
- newWorktreeRepoId = null;
-
- if (string.IsNullOrWhiteSpace(SessionName))
+ if (nameManuallyEdited) return;
+ string? auto = null;
+ if (mode == FormMode.Repo)
{
- SessionName = wt.Branch;
- _ = SessionNameChanged.InvokeAsync(SessionName);
+ if (wtMode == WtMode.Branch && !string.IsNullOrWhiteSpace(branchInput))
+ auto = branchInput.Trim();
+ else if (wtMode == WtMode.PR && !string.IsNullOrWhiteSpace(prInput))
+ auto = $"PR #{prInput.Trim().TrimStart('#')}";
+ else if (wtMode == WtMode.Existing && selectedWorktreeId != null)
+ {
+ var wt = RepoManager.Worktrees.FirstOrDefault(w => w.Id == selectedWorktreeId);
+ if (wt != null) auto = wt.Branch;
+ }
+ }
+ if (auto != null)
+ {
+ SessionName = auto;
+ _ = SessionNameChanged.InvokeAsync(auto);
}
}
- private void ClearWorktree()
+ private async Task OnNameInput(ChangeEventArgs e)
{
- selectedWorktreePath = null;
- selectedWorktreeId = null;
- selectedWorktreeBranch = null;
- sessionDirectory = "";
+ SessionName = e.Value?.ToString() ?? "";
+ nameManuallyEdited = !string.IsNullOrWhiteSpace(SessionName);
+ await SessionNameChanged.InvokeAsync(SessionName);
}
- private void StartNewWorktreeForm(string repoId)
+ private async Task OnModelSelected(string model)
{
- newWorktreeRepoId = repoId;
- newWorktreeBranch = "";
- newWorktreePr = "";
- newWorktreeMode = "branch";
- worktreeError = null;
+ SelectedModel = model;
+ await SelectedModelChanged.InvokeAsync(model);
}
- private async Task HandleNewWorktreeKeyUp(KeyboardEventArgs e)
+ private async Task HandleInputKeyUp(KeyboardEventArgs e)
{
- if (e.Key == "Enter") await CreateAndSelectWorktree();
- else if (e.Key == "Escape") newWorktreeRepoId = null;
+ if (!nameManuallyEdited) UpdateAutoName();
+ if (e.Key == "Enter") await TriggerCreate();
+ else if (e.Key == "Escape") Collapse();
}
- private async Task CreateAndSelectWorktree()
+ private async Task HandleKeyUp(KeyboardEventArgs e)
{
- if (isCreatingWorktree || newWorktreeRepoId == null) return;
- if (newWorktreeMode == "pr")
+ if (e.Key == "Escape") Collapse();
+ else if (e.Key == "Enter") await TriggerCreate();
+ }
+
+ private async Task TriggerCreate()
+ {
+ if (string.IsNullOrWhiteSpace(SessionName) || IsCreating || isCreatingWorktree) return;
+
+ var prompt = string.IsNullOrWhiteSpace(initialPrompt) ? null : initialPrompt.Trim();
+ string? repoId = null;
+ string? branchName = null;
+ int? prNumber = null;
+ string? wtId = null;
+ string? dir = mode == FormMode.Empty ? null : "";
+
+ if (mode == FormMode.Repo && selectedRepoId != null)
{
- if (!int.TryParse(newWorktreePr.Trim().TrimStart('#'), out var prNum) || prNum <= 0)
- { worktreeError = "Enter a valid PR number"; return; }
- isCreatingWorktree = true; worktreeError = null;
- try
+ repoId = selectedRepoId;
+ if (wtMode == WtMode.Auto)
{
- if (CopilotService.IsRemoteMode)
- {
- var result = await CopilotService.CreateWorktreeViaBridgeAsync(newWorktreeRepoId, null, prNum);
- var wt = new WorktreeInfo { Id = result.WorktreeId, RepoId = result.RepoId, Branch = result.Branch, Path = result.Path, PrNumber = result.PrNumber };
- RepoManager.AddRemoteWorktree(wt);
- SelectWorktree(wt);
- }
- else
- {
- var wt = await RepoManager.CreateWorktreeFromPrAsync(newWorktreeRepoId, prNum);
- SelectWorktree(wt);
- }
- if (string.IsNullOrWhiteSpace(SessionName))
- { SessionName = $"PR #{prNum}"; await SessionNameChanged.InvokeAsync(SessionName); }
+ // Auto-generate branch name from session name
+ var sanitized = System.Text.RegularExpressions.Regex.Replace(SessionName.Trim(), @"[^a-zA-Z0-9_-]", "-").Trim('-');
+ if (string.IsNullOrEmpty(sanitized)) sanitized = "session";
+ branchName = $"{sanitized}-{Guid.NewGuid().ToString()[..4]}";
}
- catch (Exception ex) { worktreeError = ex.Message; }
- finally { isCreatingWorktree = false; }
- }
- else
- {
- if (string.IsNullOrWhiteSpace(newWorktreeBranch)) return;
- isCreatingWorktree = true; worktreeError = null;
- try
+ else if (wtMode == WtMode.Branch)
{
- WorktreeInfo wt;
- if (CopilotService.IsRemoteMode)
- {
- var result = await CopilotService.CreateWorktreeViaBridgeAsync(newWorktreeRepoId, newWorktreeBranch.Trim(), null);
- wt = new WorktreeInfo { Id = result.WorktreeId, RepoId = result.RepoId, Branch = result.Branch, Path = result.Path, PrNumber = result.PrNumber };
- RepoManager.AddRemoteWorktree(wt);
- }
- else
- {
- wt = await RepoManager.CreateWorktreeAsync(newWorktreeRepoId, newWorktreeBranch.Trim());
- }
- SelectWorktree(wt);
- if (string.IsNullOrWhiteSpace(SessionName))
- { SessionName = wt.Branch; await SessionNameChanged.InvokeAsync(SessionName); }
+ if (string.IsNullOrWhiteSpace(branchInput)) { worktreeError = "Enter a branch name"; return; }
+ branchName = branchInput.Trim();
+ }
+ else if (wtMode == WtMode.PR)
+ {
+ if (!int.TryParse(prInput.Trim().TrimStart('#'), out var pr) || pr <= 0)
+ { worktreeError = "Enter a valid PR number"; return; }
+ prNumber = pr;
+ }
+ else if (wtMode == WtMode.Existing)
+ {
+ if (string.IsNullOrEmpty(selectedWorktreeId)) { worktreeError = "Select a worktree"; return; }
+ wtId = selectedWorktreeId;
}
- catch (Exception ex) { worktreeError = ex.Message; }
- finally { isCreatingWorktree = false; }
}
- }
-
- private async Task RemoveWorktree(string worktreeId)
- {
- try
+ else if (mode == FormMode.Directory)
{
- if (selectedWorktreeId == worktreeId) ClearWorktree();
- if (CopilotService.IsRemoteMode)
- await CopilotService.RemoveWorktreeViaBridgeAsync(worktreeId);
- else
- await RepoManager.RemoveWorktreeAsync(worktreeId);
+ dir = sessionDirectory;
}
- catch (Exception ex) { worktreeError = ex.Message; }
- }
- private async Task TriggerCreate()
- {
- if (!string.IsNullOrWhiteSpace(SessionName))
- {
- var prompt = string.IsNullOrWhiteSpace(initialPrompt) ? null : initialPrompt.Trim();
- await OnCreate.InvokeAsync((SessionName, SelectedModel, sessionDirectory, selectedWorktreeId, prompt));
- selectedWorktreePath = null; selectedWorktreeId = null; selectedWorktreeBranch = null;
- sessionDirectory = ""; initialPrompt = "";
- isExpanded = false; showOptions = false;
- }
- }
+ worktreeError = null;
+ await OnCreate.InvokeAsync((SessionName, SelectedModel, dir, wtId, prompt, repoId, branchName, prNumber));
- private async Task HandleKeyUp(KeyboardEventArgs e)
- {
- if (e.Key == "Escape") Collapse();
+ // Reset form
+ branchInput = ""; prInput = ""; sessionDirectory = ""; initialPrompt = "";
+ selectedWorktreeId = null; nameManuallyEdited = false;
+ isExpanded = false;
}
private async Task BrowseDirectory()
@@ -357,7 +317,7 @@ else
{
var dir = await FolderPickerService.PickFolderAsync();
if (!string.IsNullOrEmpty(dir))
- { sessionDirectory = dir; selectedWorktreePath = null; selectedWorktreeId = null; selectedWorktreeBranch = null; StateHasChanged(); }
+ { sessionDirectory = dir; StateHasChanged(); }
}
catch (Exception ex) { Console.WriteLine($"Folder picker error: {ex.Message}"); }
#else
@@ -367,7 +327,7 @@ else
public void SetDirectory(string path)
{
- sessionDirectory = path; selectedWorktreePath = null; selectedWorktreeId = null; selectedWorktreeBranch = null;
+ sessionDirectory = path;
StateHasChanged();
}
}
diff --git a/PolyPilot/Components/Layout/CreateSessionForm.razor.css b/PolyPilot/Components/Layout/CreateSessionForm.razor.css
index 43f5c06068..46b7229410 100644
--- a/PolyPilot/Components/Layout/CreateSessionForm.razor.css
+++ b/PolyPilot/Components/Layout/CreateSessionForm.razor.css
@@ -21,152 +21,192 @@
.new-session-form {
display: flex;
flex-direction: column;
- gap: 0.6rem;
+ gap: 0.5rem;
padding: 0.75rem;
border: none;
border-radius: 10px;
background: var(--surface-secondary);
}
-.ns-name {
- width: 100%;
- padding: 0.5rem 0.65rem;
- border: 1px solid transparent;
+/* === Mode Chips === */
+.ns-mode-chips {
+ display: flex;
+ gap: 0.25rem;
+ padding-bottom: 0.15rem;
+}
+
+.ns-chip {
+ flex: 1;
+ padding: 0.3rem 0.4rem;
+ border: 1px solid var(--control-border);
border-radius: 6px;
- background: var(--control-bg);
- color: var(--text-primary);
- font-size: var(--type-body);
- box-sizing: border-box;
- transition: border-color 0.15s;
+ background: none;
+ color: var(--text-dim);
+ cursor: pointer;
+ font-size: var(--type-caption1);
+ font-weight: 500;
+ text-align: center;
+ transition: all 0.15s;
+ white-space: nowrap;
}
-.ns-name:focus {
- outline: none;
- border-color: var(--accent-primary);
+.ns-chip:hover {
+ color: var(--text-primary);
+ background: var(--hover-bg);
}
-.ns-name::placeholder {
- color: var(--text-dim);
+.ns-chip.active {
+ background: var(--accent-primary);
+ color: #fff;
+ border-color: var(--accent-primary);
}
-.ns-prompt {
+/* === Repo selector === */
+.ns-repo-select {
width: 100%;
- padding: 0.45rem 0.65rem;
- border: 1px solid transparent;
+ padding: 0.35rem 0.5rem;
+ border: 1px solid var(--control-border);
border-radius: 6px;
background: var(--control-bg);
color: var(--text-primary);
font-size: var(--type-footnote);
- font-family: inherit;
- resize: vertical;
- min-height: 2.2rem;
- max-height: 6rem;
- box-sizing: border-box;
- transition: border-color 0.15s;
+ cursor: pointer;
}
-.ns-prompt:focus {
+.ns-repo-select:focus {
outline: none;
border-color: var(--accent-primary);
}
-.ns-prompt::placeholder {
- color: var(--text-dim);
-}
-
-/* === Options Panel === */
-.ns-options {
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
- padding-top: 0.25rem;
- border-top: 1px solid var(--control-border);
+.ns-repo-label {
+ font-size: var(--type-footnote);
+ color: var(--text-secondary);
+ padding: 0.15rem 0;
}
-.ns-option-group {
+/* === Worktree Segment Control === */
+.ns-wt-segment {
display: flex;
- flex-direction: column;
- gap: 0.25rem;
+ border: 1px solid var(--control-border);
+ border-radius: 6px;
+ overflow: hidden;
}
-.ns-label {
- font-size: var(--type-caption2);
+.ns-seg {
+ flex: 1;
+ padding: 0.3rem 0.2rem;
+ border: none;
+ border-right: 1px solid var(--control-border);
+ background: none;
color: var(--text-dim);
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.03em;
+ cursor: pointer;
+ font-size: var(--type-caption2);
+ font-weight: 500;
+ text-align: center;
+ transition: all 0.15s;
+ white-space: nowrap;
}
-.ns-option-btn {
- background: none;
- border: none;
- color: var(--text-secondary);
- cursor: pointer;
- font-size: var(--type-footnote);
- text-align: left;
- padding: 0.2rem 0;
+.ns-seg:last-child {
+ border-right: none;
}
-.ns-option-btn:hover {
+.ns-seg:hover {
color: var(--text-primary);
+ background: var(--hover-bg);
}
-.ns-wt-badge {
- display: flex;
- align-items: center;
- gap: 0.3rem;
+.ns-seg.active {
+ background: var(--accent-primary);
+ color: #fff;
+}
+
+/* === Shared input style === */
+.ns-input {
+ width: 100%;
+ padding: 0.4rem 0.55rem;
+ border: 1px solid var(--control-border);
+ border-radius: 6px;
+ background: var(--control-bg);
+ color: var(--text-primary);
font-size: var(--type-footnote);
- color: var(--accent-primary);
+ box-sizing: border-box;
+ transition: border-color 0.15s;
}
-.ns-badge-clear {
- background: none;
- border: none;
+.ns-input:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+}
+
+.ns-input::placeholder {
color: var(--text-dim);
- cursor: pointer;
+}
+
+.ns-hint {
font-size: var(--type-caption2);
- padding: 0 0.2rem;
+ color: var(--text-dim);
+ padding: 0.2rem 0;
+ font-style: italic;
}
-.ns-badge-clear:hover {
+.ns-name {
+ width: 100%;
+ padding: 0.5rem 0.65rem;
+ border: 1px solid transparent;
+ border-radius: 6px;
+ background: var(--control-bg);
color: var(--text-primary);
+ font-size: var(--type-body);
+ box-sizing: border-box;
+ transition: border-color 0.15s;
}
-.ns-wt-picker {
- background: var(--control-bg);
- border: 1px solid var(--control-border);
- border-radius: 6px;
- overflow: hidden;
- max-height: 200px;
- overflow-y: auto;
+.ns-name:focus {
+ outline: none;
+ border-color: var(--accent-primary);
}
-.ns-dir-row {
- display: flex;
- gap: 0.3rem;
+.ns-name::placeholder {
+ color: var(--text-dim);
}
-.ns-dir-input {
- flex: 1;
- min-width: 0;
- padding: 0.3rem 0.5rem;
- border: 1px solid var(--control-border);
- border-radius: 4px;
+.ns-prompt {
+ width: 100%;
+ padding: 0.45rem 0.65rem;
+ border: 1px solid transparent;
+ border-radius: 6px;
background: var(--control-bg);
color: var(--text-primary);
font-size: var(--type-footnote);
+ font-family: inherit;
+ resize: vertical;
+ min-height: 2.2rem;
+ max-height: 6rem;
+ box-sizing: border-box;
+ transition: border-color 0.15s;
}
-.ns-dir-input:focus {
+.ns-prompt:focus {
outline: none;
border-color: var(--accent-primary);
}
+.ns-prompt::placeholder {
+ color: var(--text-dim);
+}
+
+/* === Directory row === */
+.ns-dir-row {
+ display: flex;
+ gap: 0.3rem;
+}
+
.ns-dir-browse {
- padding: 0.3rem 0.5rem;
+ padding: 0.35rem 0.5rem;
background: var(--control-bg);
border: 1px solid var(--control-border);
- border-radius: 4px;
+ border-radius: 6px;
color: var(--text-primary);
cursor: pointer;
font-size: var(--type-footnote);
@@ -190,26 +230,10 @@
min-width: 0;
}
-.ns-options-toggle {
- background: none;
- border: none;
- color: var(--text-dim);
- cursor: pointer;
- font-size: var(--type-caption1);
- padding: 0.25rem 0.35rem;
- white-space: nowrap;
- border-radius: 4px;
- transition: all 0.15s;
-}
-
-.ns-options-toggle:hover {
- color: var(--text-primary);
- background: var(--hover-bg);
-}
-
.ns-footer-actions {
display: flex;
gap: 0.35rem;
+ margin-left: auto;
}
.ns-cancel {
@@ -256,155 +280,6 @@
padding: 0.1rem 0;
}
-/* === Worktree picker items (reused from before) === */
-.wt-repo-name {
- font-size: var(--type-caption2);
- color: var(--text-dim);
- padding: 0.3rem 0.5rem 0.1rem;
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.03em;
-}
-
-.wt-option-row {
- display: flex;
- align-items: center;
-}
-
-.wt-option-row .wt-option {
- flex: 1;
- min-width: 0;
-}
-
-.wt-option {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- width: 100%;
- padding: 0.3rem 0.5rem;
- border: none;
- background: none;
- color: var(--text-primary);
- cursor: pointer;
- font-size: var(--type-footnote);
- text-align: left;
-}
-
-.wt-option:hover {
- background: var(--hover-bg);
-}
-
-.wt-option.selected {
- background: var(--hover-bg);
-}
-
-.wt-option.wt-new {
- color: var(--accent-primary);
- font-size: var(--type-footnote);
-}
-
-.wt-delete-btn {
- background: none;
- border: none;
- color: var(--text-dim);
- cursor: pointer;
- font-size: var(--type-footnote);
- padding: 0.2rem 0.4rem;
- opacity: 0;
- transition: opacity 0.15s;
-}
-
-.wt-option-row:hover .wt-delete-btn {
- opacity: 1;
-}
-
-.wt-delete-btn:hover {
- color: #ff6b6b;
-}
-
-.wt-pr-badge {
- font-size: var(--type-caption2);
- color: var(--accent-primary);
- margin-left: auto;
-}
-
-.wt-mode-toggle {
- display: flex;
- padding: 0.2rem 0.5rem;
- gap: 0;
-}
-
-.wt-mode {
- flex: 1;
- padding: 0.2rem 0;
- border: 1px solid var(--control-border);
- background: none;
- color: var(--text-dim);
- cursor: pointer;
- font-size: var(--type-caption2);
- font-weight: 600;
- text-align: center;
-}
-
-.wt-mode:first-child {
- border-radius: 4px 0 0 4px;
-}
-
-.wt-mode:last-child {
- border-radius: 0 4px 4px 0;
- border-left: none;
-}
-
-.wt-mode.active {
- background: var(--control-bg);
- color: var(--text-primary);
- border-color: var(--accent-primary);
-}
-
-.wt-new-form {
- display: flex;
- gap: 0.3rem;
- padding: 0.25rem 0.5rem;
-}
-
-.wt-branch-input {
- flex: 1;
- min-width: 0;
- padding: 0.25rem 0.4rem;
- border: 1px solid var(--control-border);
- border-radius: 4px;
- background: var(--surface-secondary);
- color: var(--text-primary);
- font-size: var(--type-footnote);
-}
-
-.wt-branch-input:focus {
- outline: none;
- border-color: var(--accent-primary);
-}
-
-.wt-create-btn {
- padding: 0.25rem 0.5rem;
- border: none;
- border-radius: 4px;
- background: var(--accent-primary);
- color: var(--text-primary);
- cursor: pointer;
- font-size: var(--type-footnote);
- font-weight: bold;
-}
-
-.wt-create-btn:disabled {
- opacity: 0.5;
- cursor: not-allowed;
-}
-
-.wt-error {
- color: #ff6b6b;
- font-size: var(--type-caption2);
- padding: 0.15rem 0.5rem;
-}
-
/* === Mobile === */
@media (max-width: 640px) {
.new-session-btn {
@@ -420,4 +295,9 @@
.ns-name {
font-size: var(--type-callout);
}
+
+ .ns-chip {
+ font-size: var(--type-caption2);
+ padding: 0.25rem 0.3rem;
+ }
}
diff --git a/PolyPilot/Components/Layout/SessionListItem.razor b/PolyPilot/Components/Layout/SessionListItem.razor
index f032a86d42..3214bcbfc3 100644
--- a/PolyPilot/Components/Layout/SessionListItem.razor
+++ b/PolyPilot/Components/Layout/SessionListItem.razor
@@ -3,6 +3,8 @@
@using System.Diagnostics
@inject CopilotService CopilotService
@inject RepoManager RepoManager
+@inject IJSRuntime JS
+@implements IAsyncDisposable
@{
var isPinned = Meta?.IsPinned ?? false;
@@ -197,20 +199,41 @@
}
-