wsb-daemon 0.275.7622

wsb's daemon: the workbench, the GitHub mirror's schedule and peer continuity, for every workspace on the machine
<script lang="ts">
  import SettingsSection from "./SettingsSection.svelte";
  import { settings } from "../../stores/settings.svelte.js";

  const MODES = [
    { value: "auto", label: "Auto-detect" },
    { value: "custom", label: "Custom" },
    { value: "clipboard", label: "Clipboard only" },
  ] as const;

  let localMode: string = $state(settings.terminal.mode || "auto");
  let localBin: string = $state(settings.terminal.custom_bin ?? "");
  let localArgs: string = $state(settings.terminal.custom_args ?? "");

  $effect(() => {
    localMode = settings.terminal.mode || "auto";
    localBin = settings.terminal.custom_bin ?? "";
    localArgs = settings.terminal.custom_args ?? "";
  });

  async function saveTerminal() {
    await settings.save({
      terminal: {
        mode: localMode as "auto" | "custom" | "clipboard",
        custom_bin: localBin || undefined,
        custom_args: localArgs || undefined,
      },
    });
  }

  let dirty = $derived(
    localMode !== (settings.terminal.mode || "auto") ||
      localBin !== (settings.terminal.custom_bin ?? "") ||
      localArgs !== (settings.terminal.custom_args ?? ""),
  );
</script>

<SettingsSection
  title="Terminal"
  description="Configure how sessions are resumed in your terminal."
>
  <div class="setting-row">
    <span class="setting-label">Launch mode</span>
    <div class="setting-options">
      {#each MODES as opt}
        <button
          class="option-btn"
          class:active={localMode === opt.value}
          onclick={() => (localMode = opt.value)}
        >
          {opt.label}
        </button>
      {/each}
    </div>
  </div>

  {#if localMode === "custom"}
    <div class="setting-row column">
      <label class="setting-label" for="terminal-bin">Terminal binary</label>
      <input
        id="terminal-bin"
        class="setting-input"
        type="text"
        placeholder="/usr/bin/kitty"
        bind:value={localBin}
      />
    </div>

    <div class="setting-row column">
      <label class="setting-label" for="terminal-args">
        Arguments <span class="hint">(use {"{cmd}"} as placeholder)</span>
      </label>
      <input
        id="terminal-args"
        class="setting-input"
        type="text"
        placeholder="-- bash -c {"{cmd}"}"
        bind:value={localArgs}
      />
    </div>
  {/if}

  {#if dirty}
    <div class="save-row">
      <button
        class="save-btn"
        disabled={settings.saving}
        onclick={saveTerminal}
      >
        {settings.saving ? "Saving..." : "Save"}
      </button>
    </div>
  {/if}
</SettingsSection>

<style>
  .setting-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--wb-spacing-12);
  }

  .setting-row.column {
    flex-direction: column;
    align-items: flex-start;
  }

  .setting-label {
    font-size: var(--wb-font-size-12);
    font-weight: 500;
    color: var(--vscode-foreground);
    white-space: nowrap;
  }

  .hint {
    font-weight: 400;
    color: var(--vscode-disabledForeground);
  }

  .setting-options {
    display: flex;
    gap: var(--wb-spacing-4);
  }

  .option-btn {
    height: var(--wb-control-size-26);
    padding: 0 var(--wb-spacing-10);
    border-radius: var(--wsb-radius-sm);
    font-size: var(--wb-font-size-11);
    font-weight: 500;
    color: var(--vscode-disabledForeground);
    background: var(--vscode-input-background);
    border: 1px solid var(--vscode-widget-border);
    cursor: pointer;
    transition: all 0.12s;
  }

  .option-btn:hover {
    color: var(--vscode-foreground);
    background: var(--vscode-list-hoverBackground);
  }

  .option-btn.active {
    color: var(--vscode-focusBorder);
    background: color-mix(in srgb, var(--vscode-focusBorder) 10%, transparent);
    border-color: var(--vscode-focusBorder);
  }

  .setting-input {
    width: 100%;
    height: var(--wb-control-size-30);
    padding: 0 var(--wb-spacing-10);
    border-radius: var(--wsb-radius-sm);
    font-size: var(--wb-font-size-12);
    font-family: var(--wsb-font-mono, monospace);
    color: var(--vscode-editor-foreground);
    background: var(--vscode-input-background);
    border: 1px solid var(--vscode-widget-border);
    transition: border-color 0.15s;
  }

  .setting-input:focus {
    outline: none;
    border-color: var(--vscode-focusBorder);
  }

  .save-row {
    display: flex;
    justify-content: flex-end;
  }

  .save-btn {
    height: var(--wb-control-size-28);
    padding: 0 var(--wb-spacing-16);
    border-radius: var(--wsb-radius-sm);
    font-size: var(--wb-font-size-12);
    font-weight: 500;
    color: white;
    background: var(--vscode-focusBorder);
    border: none;
    cursor: pointer;
    transition: opacity 0.12s;
  }

  .save-btn:hover:not(:disabled) {
    opacity: 0.9;
  }

  .save-btn:disabled {
    opacity: 0.6;
    cursor: default;
  }
</style>