mihailik commited on
Commit
0d61133
Β·
1 Parent(s): 638c2d6

Slight tune for the menu.

Browse files
Files changed (3) hide show
  1. package.json +1 -1
  2. src/app/model-slash.css +66 -0
  3. src/app/model-slash.js +30 -37
package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "localm",
3
- "version": "1.1.30",
4
  "description": "Chat application",
5
  "scripts": {
6
  "build": "esbuild src/index.js --target=es6 --bundle --sourcemap --outfile=./index.js --format=iife --external:fs --external:path --external:child_process --external:ws --external:katex/dist/katex.min.css",
 
1
  {
2
  "name": "localm",
3
+ "version": "1.1.31",
4
  "description": "Chat application",
5
  "scripts": {
6
  "build": "esbuild src/index.js --target=es6 --bundle --sourcemap --outfile=./index.js --format=iife --external:fs --external:path --external:child_process --external:ws --external:katex/dist/katex.min.css",
src/app/model-slash.css ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .slash-menu {
2
+ position: absolute;
3
+ padding: 0;
4
+ background: white;
5
+ border: 1px solid #e5e7eb;
6
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
7
+ border-radius: 8px;
8
+ font-size: 14px;
9
+ max-height: 256px;
10
+ overflow-y: auto;
11
+ min-width: 256px;
12
+ z-index: 50;
13
+
14
+ .model-list {
15
+ margin: 0;
16
+ padding: 0;
17
+ list-style: none;
18
+
19
+ .model-entry {
20
+ padding: 8px 12px;
21
+ cursor: pointer;
22
+ display: flex;
23
+ align-items: center;
24
+ gap: 8px;
25
+ border-bottom: 1px solid #f3f4f6;
26
+
27
+ .model-icon {
28
+ font-size: 90%;
29
+ }
30
+
31
+ .model-text-container {
32
+ flex: 1;
33
+ min-width: 0;
34
+
35
+ .name {
36
+ font-weight: 500;
37
+ color: #111827;
38
+ white-space: nowrap;
39
+ overflow: hidden;
40
+ text-overflow: ellipsis;
41
+ }
42
+
43
+ .size {
44
+ font-size: 12px;
45
+ color: #6b7280;
46
+ }
47
+ }
48
+
49
+ .auth {
50
+ font-size: 10px;
51
+ color: #ea580c;
52
+ background: #fed7aa;
53
+ padding: 2px 6px;
54
+ border-radius: 4px;
55
+ }
56
+ }
57
+
58
+ .model-entry:hover {
59
+ background-color: #f0f9ff;
60
+ }
61
+
62
+ .model-entry:last-child {
63
+ border-bottom: none;
64
+ }
65
+ }
66
+ }
src/app/model-slash.js CHANGED
@@ -15,6 +15,8 @@
15
 
16
  import { slashFactory, SlashProvider } from '@milkdown/plugin-slash';
17
 
 
 
18
  /**
19
  * @typedef {{
20
  * id: string,
@@ -38,19 +40,6 @@ export function createModelSlashPlugin({ getModels, onSlashCommand }) {
38
  // Create the menu DOM element
39
  const menu = document.createElement('div');
40
  menu.className = "slash-menu";
41
- menu.style.cssText = `
42
- position: absolute;
43
- padding: 0;
44
- background: white;
45
- border: 1px solid #e5e7eb;
46
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
47
- border-radius: 8px;
48
- font-size: 14px;
49
- max-height: 256px;
50
- overflow-y: auto;
51
- min-width: 256px;
52
- z-index: 50;
53
- `;
54
 
55
  // Function to rebuild menu content
56
  function rebuildMenu() {
@@ -76,39 +65,31 @@ export function createModelSlashPlugin({ getModels, onSlashCommand }) {
76
 
77
  // Create model list
78
  const modelList = document.createElement('ul');
79
- modelList.style.cssText = "margin: 0; padding: 0; list-style: none;";
80
-
81
  availableModels.forEach((model, index) => {
82
  const item = document.createElement('li');
83
- item.style.cssText = "padding: 8px 12px; cursor: pointer; display: flex; align-items: center; gap: 8px; border-bottom: 1px solid #f3f4f6;";
84
  item.dataset.modelId = model.id;
85
-
86
- // Add hover effects
87
- item.addEventListener('mouseenter', () => {
88
- item.style.backgroundColor = '#f0f9ff';
89
- });
90
- item.addEventListener('mouseleave', () => {
91
- item.style.backgroundColor = '';
92
- });
93
-
94
  // Create icon
95
  const icon = document.createElement('span');
 
96
  icon.textContent = model.requiresAuth ? 'πŸ”’' : 'πŸ€–';
97
- icon.style.fontSize = '18px';
98
 
99
  // Create text container
100
  const textContainer = document.createElement('div');
101
- textContainer.style.cssText = "flex: 1; min-width: 0;";
102
-
103
  const name = document.createElement('div');
 
104
  name.textContent = model.name;
105
- name.style.cssText = "font-weight: 500; color: #111827; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
106
  textContainer.appendChild(name);
107
 
108
  if (model.size) {
109
  const subtitle = document.createElement('div');
 
110
  subtitle.textContent = `(${model.size})`;
111
- subtitle.style.cssText = "font-size: 12px; color: #6b7280;";
112
  textContainer.appendChild(subtitle);
113
  }
114
 
@@ -118,16 +99,11 @@ export function createModelSlashPlugin({ getModels, onSlashCommand }) {
118
  // Add auth indicator if needed
119
  if (model.requiresAuth) {
120
  const authSpan = document.createElement('span');
 
121
  authSpan.textContent = "Auth Required";
122
- authSpan.style.cssText = "font-size: 10px; color: #ea580c; background: #fed7aa; padding: 2px 6px; border-radius: 4px;";
123
  item.appendChild(authSpan);
124
  }
125
-
126
- // Remove bottom border from last item
127
- if (index === availableModels.length - 1) {
128
- item.style.borderBottom = 'none';
129
- }
130
-
131
  modelList.appendChild(item);
132
  });
133
 
@@ -163,6 +139,21 @@ export function createModelSlashPlugin({ getModels, onSlashCommand }) {
163
  offset: 8,
164
  });
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  // Configuration function for the slash plugin
167
  const slashConfig = (ctx) => {
168
  ctx.set(modelSlash.key, {
@@ -174,6 +165,8 @@ export function createModelSlashPlugin({ getModels, onSlashCommand }) {
174
  },
175
  destroy: () => {
176
  provider.destroy();
 
 
177
  },
178
  }),
179
  });
 
15
 
16
  import { slashFactory, SlashProvider } from '@milkdown/plugin-slash';
17
 
18
+ import './model-slash.css';
19
+
20
  /**
21
  * @typedef {{
22
  * id: string,
 
40
  // Create the menu DOM element
41
  const menu = document.createElement('div');
42
  menu.className = "slash-menu";
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  // Function to rebuild menu content
45
  function rebuildMenu() {
 
65
 
66
  // Create model list
67
  const modelList = document.createElement('ul');
68
+ modelList.className = 'model-list';
69
+
70
  availableModels.forEach((model, index) => {
71
  const item = document.createElement('li');
72
+ item.className = 'model-entry';
73
  item.dataset.modelId = model.id;
74
+
 
 
 
 
 
 
 
 
75
  // Create icon
76
  const icon = document.createElement('span');
77
+ icon.className = 'model-icon';
78
  icon.textContent = model.requiresAuth ? 'πŸ”’' : 'πŸ€–';
 
79
 
80
  // Create text container
81
  const textContainer = document.createElement('div');
82
+ textContainer.className = 'model-text-container';
83
+
84
  const name = document.createElement('div');
85
+ name.className = 'name';
86
  name.textContent = model.name;
 
87
  textContainer.appendChild(name);
88
 
89
  if (model.size) {
90
  const subtitle = document.createElement('div');
91
+ subtitle.className = 'size';
92
  subtitle.textContent = `(${model.size})`;
 
93
  textContainer.appendChild(subtitle);
94
  }
95
 
 
99
  // Add auth indicator if needed
100
  if (model.requiresAuth) {
101
  const authSpan = document.createElement('span');
102
+ authSpan.className = 'auth';
103
  authSpan.textContent = "Auth Required";
 
104
  item.appendChild(authSpan);
105
  }
106
+
 
 
 
 
 
107
  modelList.appendChild(item);
108
  });
109
 
 
139
  offset: 8,
140
  });
141
 
142
+ // Hide on Escape key β€” attach a document listener and remove it on destroy
143
+ function onKeyDown(e) {
144
+ if (!e) return;
145
+ const key = e.key || e.keyCode;
146
+ if (key === 'Escape' || key === 'Esc' || key === 27) {
147
+ try {
148
+ provider.hide();
149
+ } catch (err) {
150
+ // ignore
151
+ }
152
+ }
153
+ }
154
+
155
+ document.addEventListener('keydown', onKeyDown);
156
+
157
  // Configuration function for the slash plugin
158
  const slashConfig = (ctx) => {
159
  ctx.set(modelSlash.key, {
 
165
  },
166
  destroy: () => {
167
  provider.destroy();
168
+ // cleanup the document key listener
169
+ document.removeEventListener('keydown', onKeyDown);
170
  },
171
  }),
172
  });