extonlawrence commited on
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 CarbonEdit from "~icons/carbon/edit";
 
 
 
 
 
 
 
7
 
8
  const settings = useSettingsStore();
9
 
 
 
 
10
  let activePersonas = $derived(
11
- $settings.activePersonas
12
- .map(id => $settings.personas.find((p) => p.id === id))
13
- .filter(Boolean)
 
 
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 hover:bg-gray-200 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-500 dark:hover:bg-gray-700"
45
- onclick={() => goto(`${base}/settings/personas/${$settings.activePersonas[0] || $settings.personas[0]?.id || ''}`)}
 
 
 
 
 
 
 
 
46
  onmouseenter={handleMouseEnter}
47
  onmouseleave={handleMouseLeave}
48
- title="{activePersonas.length === 1 ? 'Manage personas' : ''}"
49
  >
50
- <CarbonUser class="text-xs" />
 
 
 
 
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-1 min-w-[200px] animate-in fade-in slide-in-from-bottom-2 duration-300 rounded-lg border border-gray-300 bg-white py-1.5 shadow-lg dark:border-gray-600 dark:bg-gray-800"
60
  onmouseenter={handleMouseEnter}
61
  onmouseleave={handleMouseLeave}
62
  >
63
- <div class="px-3 py-1.5 text-xs font-semibold text-gray-500 dark:text-gray-400">
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-700 transition-all duration-200 hover:bg-gray-100 hover:pl-4 dark:text-gray-300 dark:hover:bg-gray-700"
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-black dark:bg-white"></div>
74
  <span class="truncate">{persona?.name ?? "Unknown"}</span>
75
  </div>
76
- <CarbonEdit class="size-3.5 flex-shrink-0 text-gray-400 opacity-0 transition-opacity duration-200 group-hover:opacity-100 dark:text-gray-500" />
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>