Spaces:
Runtime error
Runtime error
Commit
·
62ec7ad
1
Parent(s):
7956421
Support locked personas in PersonaSelector with archived filtering
Browse files
src/lib/components/PersonaSelector.svelte
CHANGED
|
@@ -3,14 +3,26 @@
|
|
| 3 |
import { base } from "$app/paths";
|
| 4 |
import { useSettingsStore } from "$lib/stores/settings";
|
| 5 |
import CarbonUser from "~icons/carbon/user";
|
| 6 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
const settings = useSettingsStore();
|
| 9 |
|
|
|
|
|
|
|
|
|
|
| 10 |
let activePersonas = $derived(
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
.
|
|
|
|
|
|
|
| 14 |
);
|
| 15 |
|
| 16 |
let displayText = $derived(() => {
|
|
@@ -27,7 +39,7 @@
|
|
| 27 |
clearTimeout(hideTimeout);
|
| 28 |
hideTimeout = undefined;
|
| 29 |
}
|
| 30 |
-
if (activePersonas.length > 1) {
|
| 31 |
showDropdown = true;
|
| 32 |
}
|
| 33 |
}
|
|
@@ -41,13 +53,25 @@
|
|
| 41 |
|
| 42 |
<div class="relative">
|
| 43 |
<button
|
| 44 |
-
class="flex items-center gap-1.5 rounded-lg border border-gray-300 bg-gray-100 px-3 py-1.5 text-sm text-gray-400 shadow-sm
|
| 45 |
-
onclick={() =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
onmouseenter={handleMouseEnter}
|
| 47 |
onmouseleave={handleMouseLeave}
|
| 48 |
-
title="
|
| 49 |
>
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
<span class="max-w-[150px] truncate">{displayText()}</span>
|
| 52 |
</button>
|
| 53 |
|
|
@@ -56,24 +80,24 @@
|
|
| 56 |
<div
|
| 57 |
role="menu"
|
| 58 |
tabindex="-1"
|
| 59 |
-
class="absolute bottom-full left-0 mb-
|
| 60 |
onmouseenter={handleMouseEnter}
|
| 61 |
onmouseleave={handleMouseLeave}
|
| 62 |
>
|
| 63 |
-
<div class="px-3 py-1.5 text-xs font-semibold text-gray-
|
| 64 |
Active Personas
|
| 65 |
</div>
|
| 66 |
{#each activePersonas as persona (persona?.id)}
|
| 67 |
<button
|
| 68 |
type="button"
|
| 69 |
-
class="group flex w-full items-center justify-between gap-2 px-3 py-1.5 text-left text-sm text-gray-
|
| 70 |
onclick={() => goto(`${base}/settings/personas/${persona?.id || ''}`)}
|
| 71 |
>
|
| 72 |
<div class="flex items-center gap-2 truncate">
|
| 73 |
-
<div class="size-1.5 flex-shrink-0 rounded-full bg-
|
| 74 |
<span class="truncate">{persona?.name ?? "Unknown"}</span>
|
| 75 |
</div>
|
| 76 |
-
<
|
| 77 |
</button>
|
| 78 |
{/each}
|
| 79 |
</div>
|
|
|
|
| 3 |
import { base } from "$app/paths";
|
| 4 |
import { useSettingsStore } from "$lib/stores/settings";
|
| 5 |
import CarbonUser from "~icons/carbon/user";
|
| 6 |
+
import CarbonSwitcher from "~icons/carbon/switcher";
|
| 7 |
+
import CarbonLocked from "~icons/carbon/locked";
|
| 8 |
+
|
| 9 |
+
interface Props {
|
| 10 |
+
lockedPersonaId?: string;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
let { lockedPersonaId }: Props = $props();
|
| 14 |
|
| 15 |
const settings = useSettingsStore();
|
| 16 |
|
| 17 |
+
const availablePersonas = $derived($settings.personas.filter((persona) => !persona.archived));
|
| 18 |
+
|
| 19 |
+
// If locked, show only the locked persona; otherwise show active personas
|
| 20 |
let activePersonas = $derived(
|
| 21 |
+
lockedPersonaId
|
| 22 |
+
? availablePersonas.filter((persona) => persona.id === lockedPersonaId)
|
| 23 |
+
: $settings.activePersonas
|
| 24 |
+
.map((id) => availablePersonas.find((persona) => persona.id === id))
|
| 25 |
+
.filter(Boolean)
|
| 26 |
);
|
| 27 |
|
| 28 |
let displayText = $derived(() => {
|
|
|
|
| 39 |
clearTimeout(hideTimeout);
|
| 40 |
hideTimeout = undefined;
|
| 41 |
}
|
| 42 |
+
if (activePersonas.length > 1 && !lockedPersonaId) {
|
| 43 |
showDropdown = true;
|
| 44 |
}
|
| 45 |
}
|
|
|
|
| 53 |
|
| 54 |
<div class="relative">
|
| 55 |
<button
|
| 56 |
+
class="flex items-center gap-1.5 rounded-lg border border-gray-300 bg-gray-100 px-3 py-1.5 text-sm text-gray-400 shadow-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-500 {lockedPersonaId ? 'cursor-not-allowed opacity-75' : 'hover:bg-gray-200 dark:hover:bg-gray-700'}"
|
| 57 |
+
onclick={() => {
|
| 58 |
+
if (!lockedPersonaId) {
|
| 59 |
+
const firstActive = $settings.activePersonas.find((id) =>
|
| 60 |
+
availablePersonas.some((persona) => persona.id === id)
|
| 61 |
+
);
|
| 62 |
+
const fallback = availablePersonas[0]?.id ?? "";
|
| 63 |
+
goto(`${base}/settings/personas/${firstActive ?? fallback}`);
|
| 64 |
+
}
|
| 65 |
+
}}
|
| 66 |
onmouseenter={handleMouseEnter}
|
| 67 |
onmouseleave={handleMouseLeave}
|
| 68 |
+
title={lockedPersonaId ? "Persona locked in branch" : (activePersonas.length === 1 ? 'Manage personas' : '')}
|
| 69 |
>
|
| 70 |
+
{#if lockedPersonaId}
|
| 71 |
+
<CarbonLocked class="text-xs" />
|
| 72 |
+
{:else}
|
| 73 |
+
<CarbonUser class="text-xs" />
|
| 74 |
+
{/if}
|
| 75 |
<span class="max-w-[150px] truncate">{displayText()}</span>
|
| 76 |
</button>
|
| 77 |
|
|
|
|
| 80 |
<div
|
| 81 |
role="menu"
|
| 82 |
tabindex="-1"
|
| 83 |
+
class="absolute bottom-full left-0 mb-2 min-w-[200px] animate-in fade-in slide-in-from-bottom-2 duration-300 rounded-lg border border-gray-300 bg-gray-100 py-1.5 shadow-lg dark:border-gray-600 dark:bg-gray-800"
|
| 84 |
onmouseenter={handleMouseEnter}
|
| 85 |
onmouseleave={handleMouseLeave}
|
| 86 |
>
|
| 87 |
+
<div class="px-3 py-1.5 text-xs font-semibold text-gray-400 dark:text-gray-500">
|
| 88 |
Active Personas
|
| 89 |
</div>
|
| 90 |
{#each activePersonas as persona (persona?.id)}
|
| 91 |
<button
|
| 92 |
type="button"
|
| 93 |
+
class="group flex w-full items-center justify-between gap-2 px-3 py-1.5 text-left text-sm text-gray-400 transition-all duration-200 hover:bg-gray-200 hover:pl-4 hover:text-gray-600 dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-gray-300"
|
| 94 |
onclick={() => goto(`${base}/settings/personas/${persona?.id || ''}`)}
|
| 95 |
>
|
| 96 |
<div class="flex items-center gap-2 truncate">
|
| 97 |
+
<div class="size-1.5 flex-shrink-0 rounded-full bg-gray-400 dark:bg-gray-500"></div>
|
| 98 |
<span class="truncate">{persona?.name ?? "Unknown"}</span>
|
| 99 |
</div>
|
| 100 |
+
<CarbonSwitcher class="size-3.5 flex-shrink-0 text-gray-400 opacity-0 transition-opacity duration-200 group-hover:opacity-100 dark:text-gray-500" />
|
| 101 |
</button>
|
| 102 |
{/each}
|
| 103 |
</div>
|