llms-py 3.0.0__py3-none-any.whl → 3.0.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. llms/__pycache__/main.cpython-314.pyc +0 -0
  2. llms/index.html +37 -26
  3. llms/llms.json +21 -70
  4. llms/main.py +731 -1426
  5. llms/providers.json +1 -1
  6. llms/{extensions/analytics/ui/index.mjs → ui/Analytics.mjs} +238 -154
  7. llms/ui/App.mjs +63 -133
  8. llms/ui/Avatar.mjs +86 -0
  9. llms/ui/Brand.mjs +52 -0
  10. llms/ui/ChatPrompt.mjs +597 -0
  11. llms/ui/Main.mjs +862 -0
  12. llms/ui/OAuthSignIn.mjs +61 -0
  13. llms/ui/ProviderIcon.mjs +36 -0
  14. llms/ui/ProviderStatus.mjs +104 -0
  15. llms/{extensions/app/ui → ui}/Recents.mjs +57 -82
  16. llms/ui/{modules/chat/SettingsDialog.mjs → SettingsDialog.mjs} +9 -9
  17. llms/{extensions/app/ui/index.mjs → ui/Sidebar.mjs} +57 -122
  18. llms/ui/SignIn.mjs +65 -0
  19. llms/ui/Welcome.mjs +8 -0
  20. llms/ui/ai.mjs +13 -117
  21. llms/ui/app.css +49 -1776
  22. llms/ui/index.mjs +171 -87
  23. llms/ui/lib/charts.mjs +13 -9
  24. llms/ui/lib/servicestack-vue.mjs +3 -3
  25. llms/ui/lib/vue.min.mjs +9 -10
  26. llms/ui/lib/vue.mjs +1602 -1763
  27. llms/ui/markdown.mjs +2 -10
  28. llms/ui/model-selector.mjs +686 -0
  29. llms/ui/tailwind.input.css +1 -55
  30. llms/ui/threadStore.mjs +583 -0
  31. llms/ui/utils.mjs +118 -113
  32. llms/ui.json +1069 -0
  33. {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.dist-info}/METADATA +1 -1
  34. llms_py-3.0.0b2.dist-info/RECORD +58 -0
  35. llms/extensions/app/README.md +0 -20
  36. llms/extensions/app/__init__.py +0 -530
  37. llms/extensions/app/__pycache__/__init__.cpython-314.pyc +0 -0
  38. llms/extensions/app/__pycache__/db.cpython-314.pyc +0 -0
  39. llms/extensions/app/__pycache__/db_manager.cpython-314.pyc +0 -0
  40. llms/extensions/app/db.py +0 -644
  41. llms/extensions/app/db_manager.py +0 -195
  42. llms/extensions/app/requests.json +0 -9073
  43. llms/extensions/app/threads.json +0 -15290
  44. llms/extensions/app/ui/threadStore.mjs +0 -411
  45. llms/extensions/core_tools/CALCULATOR.md +0 -32
  46. llms/extensions/core_tools/__init__.py +0 -598
  47. llms/extensions/core_tools/__pycache__/__init__.cpython-314.pyc +0 -0
  48. llms/extensions/core_tools/ui/codemirror/addon/edit/closebrackets.js +0 -201
  49. llms/extensions/core_tools/ui/codemirror/addon/edit/closetag.js +0 -185
  50. llms/extensions/core_tools/ui/codemirror/addon/edit/continuelist.js +0 -101
  51. llms/extensions/core_tools/ui/codemirror/addon/edit/matchbrackets.js +0 -160
  52. llms/extensions/core_tools/ui/codemirror/addon/edit/matchtags.js +0 -66
  53. llms/extensions/core_tools/ui/codemirror/addon/edit/trailingspace.js +0 -27
  54. llms/extensions/core_tools/ui/codemirror/addon/selection/active-line.js +0 -72
  55. llms/extensions/core_tools/ui/codemirror/addon/selection/mark-selection.js +0 -119
  56. llms/extensions/core_tools/ui/codemirror/addon/selection/selection-pointer.js +0 -98
  57. llms/extensions/core_tools/ui/codemirror/doc/docs.css +0 -225
  58. llms/extensions/core_tools/ui/codemirror/doc/source_sans.woff +0 -0
  59. llms/extensions/core_tools/ui/codemirror/lib/codemirror.css +0 -344
  60. llms/extensions/core_tools/ui/codemirror/lib/codemirror.js +0 -9884
  61. llms/extensions/core_tools/ui/codemirror/mode/clike/clike.js +0 -942
  62. llms/extensions/core_tools/ui/codemirror/mode/javascript/index.html +0 -118
  63. llms/extensions/core_tools/ui/codemirror/mode/javascript/javascript.js +0 -962
  64. llms/extensions/core_tools/ui/codemirror/mode/javascript/typescript.html +0 -62
  65. llms/extensions/core_tools/ui/codemirror/mode/python/python.js +0 -402
  66. llms/extensions/core_tools/ui/codemirror/theme/dracula.css +0 -40
  67. llms/extensions/core_tools/ui/codemirror/theme/mocha.css +0 -135
  68. llms/extensions/core_tools/ui/index.mjs +0 -650
  69. llms/extensions/gallery/README.md +0 -61
  70. llms/extensions/gallery/__init__.py +0 -61
  71. llms/extensions/gallery/__pycache__/__init__.cpython-314.pyc +0 -0
  72. llms/extensions/gallery/__pycache__/db.cpython-314.pyc +0 -0
  73. llms/extensions/gallery/db.py +0 -298
  74. llms/extensions/gallery/ui/index.mjs +0 -482
  75. llms/extensions/katex/README.md +0 -39
  76. llms/extensions/katex/__init__.py +0 -6
  77. llms/extensions/katex/__pycache__/__init__.cpython-314.pyc +0 -0
  78. llms/extensions/katex/ui/README.md +0 -125
  79. llms/extensions/katex/ui/contrib/auto-render.js +0 -338
  80. llms/extensions/katex/ui/contrib/auto-render.min.js +0 -1
  81. llms/extensions/katex/ui/contrib/auto-render.mjs +0 -244
  82. llms/extensions/katex/ui/contrib/copy-tex.js +0 -127
  83. llms/extensions/katex/ui/contrib/copy-tex.min.js +0 -1
  84. llms/extensions/katex/ui/contrib/copy-tex.mjs +0 -105
  85. llms/extensions/katex/ui/contrib/mathtex-script-type.js +0 -109
  86. llms/extensions/katex/ui/contrib/mathtex-script-type.min.js +0 -1
  87. llms/extensions/katex/ui/contrib/mathtex-script-type.mjs +0 -24
  88. llms/extensions/katex/ui/contrib/mhchem.js +0 -3213
  89. llms/extensions/katex/ui/contrib/mhchem.min.js +0 -1
  90. llms/extensions/katex/ui/contrib/mhchem.mjs +0 -3109
  91. llms/extensions/katex/ui/contrib/render-a11y-string.js +0 -887
  92. llms/extensions/katex/ui/contrib/render-a11y-string.min.js +0 -1
  93. llms/extensions/katex/ui/contrib/render-a11y-string.mjs +0 -800
  94. llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.ttf +0 -0
  95. llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff +0 -0
  96. llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  97. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  98. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  99. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  100. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  101. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  102. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  103. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  104. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  105. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  106. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  107. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  108. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  109. llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.ttf +0 -0
  110. llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff +0 -0
  111. llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff2 +0 -0
  112. llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  113. llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  114. llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  115. llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.ttf +0 -0
  116. llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff +0 -0
  117. llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff2 +0 -0
  118. llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.ttf +0 -0
  119. llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff +0 -0
  120. llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff2 +0 -0
  121. llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  122. llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  123. llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  124. llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.ttf +0 -0
  125. llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff +0 -0
  126. llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff2 +0 -0
  127. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  128. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  129. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  130. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  131. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  132. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  133. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  134. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  135. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  136. llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.ttf +0 -0
  137. llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff +0 -0
  138. llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff2 +0 -0
  139. llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.ttf +0 -0
  140. llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff +0 -0
  141. llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  142. llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.ttf +0 -0
  143. llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff +0 -0
  144. llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  145. llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.ttf +0 -0
  146. llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff +0 -0
  147. llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  148. llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.ttf +0 -0
  149. llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff +0 -0
  150. llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  151. llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  152. llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  153. llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  154. llms/extensions/katex/ui/index.mjs +0 -92
  155. llms/extensions/katex/ui/katex-swap.css +0 -1230
  156. llms/extensions/katex/ui/katex-swap.min.css +0 -1
  157. llms/extensions/katex/ui/katex.css +0 -1230
  158. llms/extensions/katex/ui/katex.js +0 -19080
  159. llms/extensions/katex/ui/katex.min.css +0 -1
  160. llms/extensions/katex/ui/katex.min.js +0 -1
  161. llms/extensions/katex/ui/katex.min.mjs +0 -1
  162. llms/extensions/katex/ui/katex.mjs +0 -18547
  163. llms/extensions/providers/__init__.py +0 -18
  164. llms/extensions/providers/__pycache__/__init__.cpython-314.pyc +0 -0
  165. llms/extensions/providers/__pycache__/anthropic.cpython-314.pyc +0 -0
  166. llms/extensions/providers/__pycache__/chutes.cpython-314.pyc +0 -0
  167. llms/extensions/providers/__pycache__/google.cpython-314.pyc +0 -0
  168. llms/extensions/providers/__pycache__/nvidia.cpython-314.pyc +0 -0
  169. llms/extensions/providers/__pycache__/openai.cpython-314.pyc +0 -0
  170. llms/extensions/providers/__pycache__/openrouter.cpython-314.pyc +0 -0
  171. llms/extensions/providers/anthropic.py +0 -229
  172. llms/extensions/providers/chutes.py +0 -155
  173. llms/extensions/providers/google.py +0 -378
  174. llms/extensions/providers/nvidia.py +0 -105
  175. llms/extensions/providers/openai.py +0 -156
  176. llms/extensions/providers/openrouter.py +0 -72
  177. llms/extensions/system_prompts/README.md +0 -22
  178. llms/extensions/system_prompts/__init__.py +0 -45
  179. llms/extensions/system_prompts/__pycache__/__init__.cpython-314.pyc +0 -0
  180. llms/extensions/system_prompts/ui/index.mjs +0 -280
  181. llms/extensions/system_prompts/ui/prompts.json +0 -1067
  182. llms/extensions/tools/__init__.py +0 -5
  183. llms/extensions/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  184. llms/extensions/tools/ui/index.mjs +0 -204
  185. llms/providers-extra.json +0 -356
  186. llms/ui/ctx.mjs +0 -365
  187. llms/ui/modules/chat/ChatBody.mjs +0 -691
  188. llms/ui/modules/chat/index.mjs +0 -828
  189. llms/ui/modules/layout.mjs +0 -243
  190. llms/ui/modules/model-selector.mjs +0 -851
  191. llms_py-3.0.0.dist-info/RECORD +0 -202
  192. {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.dist-info}/WHEEL +0 -0
  193. {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.dist-info}/entry_points.txt +0 -0
  194. {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.dist-info}/licenses/LICENSE +0 -0
  195. {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.dist-info}/top_level.txt +0 -0
llms/ui/App.mjs CHANGED
@@ -1,119 +1,42 @@
1
- import { ref, computed, watch, inject, onMounted, onUnmounted } from "vue"
1
+ import { inject, ref, watch, onMounted, onUnmounted } from "vue"
2
2
  import { useRouter, useRoute } from "vue-router"
3
- import { AppContext } from "./ctx.mjs"
4
-
5
- // Vertical Sidebar Icons
6
- const LeftBar = {
7
- template: `
8
- <div class="select-none flex flex-col space-y-2 pt-2.5 px-1">
9
- <div v-for="(icon, id) in $ctx.left" :key="id" class="relative flex items-center justify-center">
10
- <component :is="icon.component"
11
- class="size-7 p-1 cursor-pointer text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 rounded block"
12
- :class="{ 'bg-gray-200 dark:bg-gray-700' : icon.isActive({ ...$layout }) }"
13
- @mouseenter="tooltip = icon.id"
14
- @mouseleave="tooltip = ''"
15
- />
16
- <div v-if="tooltip === icon.id && !icon.isActive({ ...$layout })"
17
- class="absolute left-full top-1/2 -translate-y-1/2 ml-2 px-2 py-1 text-xs text-white bg-gray-900 dark:bg-gray-800 rounded shadow-md z-50 whitespace-nowrap pointer-events-none" style="z-index: 60">
18
- {{icon.title ?? icon.name}}
19
- </div>
20
- </div>
21
- </div>
22
- `,
23
- setup() {
24
- const tooltip = ref('')
25
- return {
26
- tooltip,
27
- }
28
- }
29
- }
30
-
31
- const LeftPanel = {
32
- template: `
33
- <div v-if="component" class="flex flex-col h-full border-r border-gray-200 dark:border-gray-700">
34
- <button type="button" class="absolute top-2 right-2 p-1 rounded-md text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-700 lg:hidden z-20">
35
- <svg class="size-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
36
- </button>
37
- <component :is="component" />
38
- </div>
39
- `,
40
- setup() {
41
- /**@type {AppContext} */
42
- const ctx = inject('ctx')
43
- const component = computed(() => ctx.component(ctx.layout.left))
44
- return {
45
- component,
46
- }
47
- }
48
- }
49
-
50
- const TopBar = {
51
- template: `
52
- <div class="select-none flex space-x-1">
53
- <div v-for="(icon, id) in $ctx.top" :key="id" class="relative flex items-center justify-center">
54
- <component :is="icon.component"
55
- class="size-7 p-1 cursor-pointer text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 block border border-transparent"
56
- :class="{ 'bg-gray-100 dark:bg-gray-800 border-gray-300 dark:border-gray-600 rounded' : icon.isActive({ ...$layout }) }"
57
- @mouseenter="tooltip = icon.id"
58
- @mouseleave="tooltip = ''"
59
- />
60
- <div v-if="tooltip === icon.id && !icon.isActive({ ...$layout })"
61
- class="absolute top-full mt-2 px-2 py-1 text-xs text-white bg-gray-900 dark:bg-gray-800 rounded shadow-md z-50 whitespace-nowrap pointer-events-none"
62
- :class="last2.includes(id) ? 'right-0' : 'left-1/2 -translate-x-1/2'">
63
- {{icon.title ?? icon.name}}
64
- </div>
65
- </div>
66
- </div>
67
- `,
68
- setup() {
69
- const tooltip = ref('')
70
- const last2 = ref(Object.keys($ctx.top).slice(-2))
71
- return {
72
- tooltip,
73
- last2,
74
- }
75
- }
76
- }
77
-
78
- const TopPanel = {
79
- template: `
80
- <component v-if="component" :is="component" class="mb-2" />
81
- `,
82
- setup() {
83
- /**@type {AppContext} */
84
- const ctx = inject('ctx')
85
- const component = computed(() => ctx.component(ctx.layout.top))
86
- return {
87
- component,
88
- }
89
- }
90
- }
3
+ import Sidebar from "./Sidebar.mjs"
91
4
 
92
5
  export default {
93
6
  components: {
94
- LeftBar,
95
- LeftPanel,
96
- TopBar,
97
- TopPanel,
7
+ Sidebar,
98
8
  },
99
- setup() {
9
+ props: ['config', 'models'],
10
+ setup(props) {
100
11
  const router = useRouter()
101
12
  const route = useRoute()
102
13
 
103
- /**@type {AppContext} */
104
14
  const ctx = inject('ctx')
105
15
  const ai = ctx.ai
106
16
  const isMobile = ref(false)
107
17
  const modal = ref()
108
18
 
109
19
  const checkMobile = () => {
110
- //const wasMobile = isMobile.value
111
- isMobile.value = window.innerWidth < 640 // sm breakpoint
20
+ const wasMobile = isMobile.value
21
+ isMobile.value = window.innerWidth < 1024 // lg breakpoint
112
22
 
113
- //console.log('checkMobile', wasMobile, isMobile.value)
114
23
  // Only auto-adjust sidebar state when transitioning between mobile/desktop
24
+ if (wasMobile !== isMobile.value) {
25
+ if (isMobile.value) {
26
+ ai.isSidebarOpen = false
27
+ } else {
28
+ ai.isSidebarOpen = true
29
+ }
30
+ }
31
+ }
32
+
33
+ const toggleSidebar = () => {
34
+ ai.isSidebarOpen = !ai.isSidebarOpen
35
+ }
36
+
37
+ const closeSidebar = () => {
115
38
  if (isMobile.value) {
116
- ctx.toggleLayout('left', false)
39
+ ai.isSidebarOpen = false
117
40
  }
118
41
  }
119
42
 
@@ -135,54 +58,61 @@ export default {
135
58
 
136
59
  watch(() => route.query.open, (newVal) => {
137
60
  modal.value = ctx.modalComponents[newVal]
138
- console.log('open', newVal, modal.value)
139
- })
140
-
141
- watch(() => ctx.state.selectedModel, (newVal) => {
142
- ctx.chat.setSelectedModel(ctx.chat.getModel(newVal))
61
+ console.log('open', newVal)
143
62
  })
144
63
 
145
- return { ai, modal, isMobile, closeModal }
64
+ return { ai, modal, isMobile, toggleSidebar, closeSidebar, closeModal }
146
65
  },
147
66
  template: `
148
- <div class="flex h-screen">
67
+ <div class="flex h-screen bg-white dark:bg-gray-900">
149
68
  <!-- Mobile Overlay -->
150
- <div v-if="isMobile && $ctx.layoutVisible('left') && $ai.hasAccess"
151
- @click="$ctx.toggleLayout('left')"
152
- :class="$ctx.cls('mobile-overlay', 'fixed inset-0 bg-black/50 z-40 lg:hidden')"
69
+ <div
70
+ v-if="isMobile && ai.isSidebarOpen && !(ai.requiresAuth && !ai.auth)"
71
+ @click="closeSidebar"
72
+ class="fixed inset-0 bg-black/50 z-40 lg:hidden"
153
73
  ></div>
154
74
 
155
- <div v-if="$ai.hasAccess" id="sidebar" :class="$ctx.cls('sidebar', 'z-100 relative flex bg-gray-50 dark:bg-gray-800')">
156
- <LeftBar id="left-bar" />
157
- <LeftPanel id="left-panel"
158
- v-if="$ai.hasAccess && $ctx.layoutVisible('left')"
159
- :class="[
160
- 'transition-transform duration-300 ease-in-out z-50',
161
- 'w-72 xl:w-80 flex-shrink-0',
162
- 'lg:relative',
163
- 'fixed inset-y-0 left-[2.25rem] lg:left-0',
164
- 'bg-gray-50 dark:bg-gray-800'
165
- ]"
166
- />
75
+ <!-- Sidebar (hidden when auth required and not authenticated) -->
76
+ <div
77
+ v-if="!(ai.requiresAuth && !ai.auth) && ai.isSidebarOpen"
78
+ :class="[
79
+ 'transition-transform duration-300 ease-in-out z-50',
80
+ 'w-72 xl:w-80 flex-shrink-0',
81
+ 'lg:relative',
82
+ 'fixed inset-y-0 left-0'
83
+ ]"
84
+ >
85
+ <Sidebar @thread-selected="closeSidebar" @toggle-sidebar="toggleSidebar" />
167
86
  </div>
168
87
 
169
88
  <!-- Main Area -->
170
- <div id="main" :class="$ctx.cls('main', 'flex-1 flex flex-col')">
171
- <div id="main-inner" :class="$ctx.cls('main-inner', 'flex flex-col h-full w-full overflow-hidden')">
172
- <div v-if="$ai.hasAccess" id="header" :class="$ctx.cls('header', 'py-1 pr-1 flex items-center justify-between shrink-0')">
173
- <div>
174
- <ModelSelector :models="$state.models" v-model="$state.selectedModel" />
89
+ <div class="flex-1 flex flex-col">
90
+ <!-- Collapsed Sidebar Toggle Button -->
91
+ <div
92
+ v-if="!(ai.requiresAuth && !ai.auth) && !ai.isSidebarOpen"
93
+ class="fixed top-4 left-0"
94
+ >
95
+ <button type="button"
96
+ @click="toggleSidebar"
97
+ class="group p-1 text-gray-500 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
98
+ title="Open sidebar"
99
+ >
100
+ <div class="relative w-5 h-5">
101
+ <!-- Default sidebar icon -->
102
+ <svg class="absolute inset-0 group-hover:hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
103
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
104
+ <line x1="9" y1="3" x2="9" y2="21"></line>
105
+ </svg>
106
+ <!-- Hover state: |→ icon -->
107
+ <svg class="absolute inset-0 hidden group-hover:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m17.172 11l-4.657-4.657l1.414-1.414L21 12l-7.071 7.071l-1.414-1.414L17.172 13H8v-2zM4 19V5h2v14z"/></svg>
175
108
  </div>
176
- <TopBar id="top-bar" />
177
- </div>
178
- <TopPanel v-if="$ai.hasAccess" id="top-panel" :class="$ctx.cls('top-panel', 'shrink-0')" />
179
- <div id="page" :class="$ctx.cls('page', 'flex-1 overflow-y-auto min-h-0 flex flex-col')">
180
- <RouterView class="h-full" />
181
- </div>
109
+ </button>
182
110
  </div>
111
+
112
+ <RouterView />
183
113
  </div>
184
114
 
185
- <component v-if="modal" :is="modal" :class="$ctx.cls('modal', '!z-[200]')" @done="closeModal" />
115
+ <component v-if="modal" :is="modal" @done="closeModal" />
186
116
  </div>
187
117
  `,
188
118
  }
llms/ui/Avatar.mjs ADDED
@@ -0,0 +1,86 @@
1
+ import { computed, inject, ref, onMounted, onUnmounted } from "vue"
2
+
3
+ export default {
4
+ template: `
5
+ <div v-if="$ai.auth?.profileUrl" class="relative" ref="avatarContainer">
6
+ <img
7
+ @click.stop="toggleMenu"
8
+ :src="$ai.auth.profileUrl"
9
+ :title="authTitle"
10
+ class="size-8 rounded-full cursor-pointer hover:ring-2 hover:ring-gray-300"
11
+ />
12
+ <div
13
+ v-if="showMenu"
14
+ @click.stop
15
+ class="absolute right-0 mt-2 w-48 bg-white dark:bg-gray-800 rounded-md shadow-lg py-1 z-50 border border-gray-200 dark:border-gray-700"
16
+ >
17
+ <div class="px-4 py-2 text-sm text-gray-700 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">
18
+ <div class="font-medium whitespace-nowrap overflow-hidden text-ellipsis">{{ $ai.auth.displayName || $ai.auth.userName }}</div>
19
+ <div class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap overflow-hidden text-ellipsis">{{ $ai.auth.email }}</div>
20
+ </div>
21
+ <button type="button"
22
+ @click="handleLogout"
23
+ class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center whitespace-nowrap"
24
+ >
25
+ <svg class="w-4 h-4 mr-2 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
26
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
27
+ </svg>
28
+ Sign Out
29
+ </button>
30
+ </div>
31
+ </div>
32
+ `,
33
+ setup() {
34
+ const ctx = inject('ctx')
35
+ const ai = ctx.ai
36
+ const showMenu = ref(false)
37
+ const avatarContainer = ref(null)
38
+
39
+ const authTitle = computed(() => {
40
+ if (!ai.auth) return ''
41
+ const { userId, userName, displayName, bearerToken, roles } = ai.auth
42
+ const name = userName || displayName
43
+ const prefix = roles && roles.includes('Admin') ? 'Admin' : 'Name'
44
+ const sb = [
45
+ name ? `${prefix}: ${name}` : '',
46
+ `API Key: ${bearerToken}`,
47
+ `${userId}`,
48
+ ]
49
+ return sb.filter(x => x).join('\n')
50
+ })
51
+
52
+ function toggleMenu() {
53
+ showMenu.value = !showMenu.value
54
+ }
55
+
56
+ async function handleLogout() {
57
+ showMenu.value = false
58
+ await ai.signOut()
59
+ // Reload the page to show sign-in screen
60
+ window.location.reload()
61
+ }
62
+
63
+ // Close menu when clicking outside
64
+ const handleClickOutside = (event) => {
65
+ if (showMenu.value && avatarContainer.value && !avatarContainer.value.contains(event.target)) {
66
+ showMenu.value = false
67
+ }
68
+ }
69
+
70
+ onMounted(() => {
71
+ document.addEventListener('click', handleClickOutside)
72
+ })
73
+
74
+ onUnmounted(() => {
75
+ document.removeEventListener('click', handleClickOutside)
76
+ })
77
+
78
+ return {
79
+ authTitle,
80
+ handleLogout,
81
+ showMenu,
82
+ toggleMenu,
83
+ avatarContainer,
84
+ }
85
+ }
86
+ }
llms/ui/Brand.mjs ADDED
@@ -0,0 +1,52 @@
1
+ export default {
2
+ template:`
3
+ <div class="flex-shrink-0 pl-2 pr-4 py-4 border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 min-h-16 select-none">
4
+ <div class="flex items-center justify-between">
5
+ <div class="flex items-center space-x-2">
6
+ <button type="button"
7
+ @click="$emit('toggle-sidebar')"
8
+ class="group relative text-gray-500 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
9
+ title="Collapse sidebar"
10
+ >
11
+ <div class="relative size-5">
12
+ <!-- Default sidebar icon -->
13
+ <svg class="absolute inset-0 group-hover:hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
14
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
15
+ <line x1="9" y1="3" x2="9" y2="21"></line>
16
+ </svg>
17
+ <!-- Hover state: |← icon -->
18
+ <svg class="absolute inset-0 hidden group-hover:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m10.071 4.929l1.414 1.414L6.828 11H16v2H6.828l4.657 4.657l-1.414 1.414L3 12zM18.001 19V5h2v14z"/></svg>
19
+ </div>
20
+ </button>
21
+
22
+ <button type="button"
23
+ @click="$emit('home')"
24
+ class="text-lg font-semibold text-gray-900 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
25
+ title="Go back to initial state"
26
+ >
27
+ History
28
+ </button>
29
+ </div>
30
+
31
+ <div class="flex items-center space-x-2">
32
+ <button type="button"
33
+ @click="$emit('analytics')"
34
+ class="text-gray-900 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
35
+ title="Analytics"
36
+ >
37
+ <svg class="size-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M5 22a1 1 0 0 1-1-1v-8a1 1 0 0 1 2 0v8a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1V3a1 1 0 0 1 2 0v18a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1V9a1 1 0 0 1 2 0v12a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1v-4a1 1 0 0 1 2 0v4a1 1 0 0 1-1 1"/></svg>
38
+ </button>
39
+
40
+ <button type="button"
41
+ @click="$emit('new')"
42
+ class="text-gray-900 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
43
+ title="New Chat"
44
+ >
45
+ <svg class="size-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"/></g></svg>
46
+ </button>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ `,
51
+ emits:['home','new','analytics','toggle-sidebar'],
52
+ }