@industry-theme/alexandria-panels 0.1.22 → 0.1.24

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.
@@ -3,7 +3,7 @@
3
3
  try {
4
4
  if (typeof document != "undefined") {
5
5
  var elementStyle = document.createElement("style");
6
- elementStyle.appendChild(document.createTextNode("/* Container query for responsive LocalProjectCard */\n.local-projects-panel {\n container-type: inline-size;\n container-name: local-projects;\n height: 100%;\n}\n\n/* Animated underline that grows from left on hover */\n.local-project-card .project-name-underline {\n position: relative;\n text-decoration: none;\n}\n\n.local-project-card .project-name-underline::after {\n content: '';\n position: absolute;\n left: 0;\n bottom: -3px;\n width: 0;\n height: 2px;\n background-color: var(--underline-color);\n transition: width 0.2s ease-out;\n}\n\n.local-project-card:hover .project-name-underline::after {\n width: 100%;\n}\n\n/* Compact mode when container is 400px or less */\n@container local-projects (max-width: 400px) {\n .local-projects-panel {\n padding: 8px !important;\n gap: 8px !important;\n }\n\n .local-projects-list {\n gap: 8px !important;\n }\n\n .local-project-card {\n padding: 8px !important;\n }\n}"));
6
+ elementStyle.appendChild(document.createTextNode("/* Container query for responsive LocalProjectCard */\n.local-projects-panel {\n container-type: inline-size;\n container-name: local-projects;\n height: 100%;\n}\n\n/* Animated underline that grows from left on hover */\n.local-project-card .project-name-underline {\n position: relative;\n text-decoration: none;\n}\n\n.local-project-card .project-name-underline::after {\n content: '';\n position: absolute;\n left: 0;\n bottom: -3px;\n width: 0;\n height: 2px;\n background-color: var(--underline-color);\n transition: width 0.2s ease-out;\n}\n\n.local-project-card:hover .project-name-underline::after {\n width: 100%;\n}\n\n/* Compact mode when container is 400px or less */\n@container local-projects (max-width: 400px) {\n .local-projects-panel {\n padding: 8px !important;\n gap: 8px !important;\n }\n\n .local-projects-list {\n gap: 8px !important;\n }\n\n .local-project-card {\n padding: 8px !important;\n }\n}\n/* Shared Panel Styles */\n\n/* Header button hover states */\n.header-button {\n transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;\n}\n\n.header-button:not(.active):hover {\n color: var(--theme-text) !important;\n}\n\n/* Search input focus state */\n.search-input:focus {\n border-color: var(--theme-primary) !important;\n}\n\n/* Clear filter button hover */\n.clear-filter-button {\n transition: color 0.2s ease;\n}\n\n.clear-filter-button:hover {\n color: var(--theme-text) !important;\n}\n\n/* Search overlay animation - grows from right to left */\n.search-overlay {\n animation: searchExpand 0.2s ease-out forwards;\n}\n\n@keyframes searchExpand {\n from {\n clip-path: inset(0 0 0 100%);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n}"));
7
7
  document.head.appendChild(elementStyle);
8
8
  }
9
9
  } catch (e) {
@@ -11,7 +11,7 @@
11
11
  }
12
12
  })();
13
13
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
14
- import React2, { createContext, useContext, forwardRef, createElement, useState, useMemo, useCallback, useEffect } from "react";
14
+ import React2, { createContext, useContext, forwardRef, createElement, useState, useCallback, useMemo, useEffect } from "react";
15
15
  var ThemeContext;
16
16
  var getThemeContext = () => {
17
17
  if (typeof window !== "undefined") {
@@ -140,7 +140,7 @@ const createLucideIcon = (iconName, iconNode) => {
140
140
  * This source code is licensed under the ISC license.
141
141
  * See the LICENSE file in the root directory of this source tree.
142
142
  */
143
- const __iconNode$v = [
143
+ const __iconNode$w = [
144
144
  ["path", { d: "M10 12h4", key: "a56b0p" }],
145
145
  ["path", { d: "M10 8h4", key: "1sr2af" }],
146
146
  ["path", { d: "M14 21v-3a2 2 0 0 0-4 0v3", key: "1rgiei" }],
@@ -153,132 +153,132 @@ const __iconNode$v = [
153
153
  ],
154
154
  ["path", { d: "M6 21V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v16", key: "16ra0t" }]
155
155
  ];
156
- const Building2 = createLucideIcon("building-2", __iconNode$v);
156
+ const Building2 = createLucideIcon("building-2", __iconNode$w);
157
157
  /**
158
158
  * @license lucide-react v0.552.0 - ISC
159
159
  *
160
160
  * This source code is licensed under the ISC license.
161
161
  * See the LICENSE file in the root directory of this source tree.
162
162
  */
163
- const __iconNode$u = [
163
+ const __iconNode$v = [
164
164
  ["path", { d: "M8 2v4", key: "1cmpym" }],
165
165
  ["path", { d: "M16 2v4", key: "4m81vk" }],
166
166
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
167
167
  ["path", { d: "M3 10h18", key: "8toen8" }]
168
168
  ];
169
- const Calendar = createLucideIcon("calendar", __iconNode$u);
169
+ const Calendar = createLucideIcon("calendar", __iconNode$v);
170
170
  /**
171
171
  * @license lucide-react v0.552.0 - ISC
172
172
  *
173
173
  * This source code is licensed under the ISC license.
174
174
  * See the LICENSE file in the root directory of this source tree.
175
175
  */
176
- const __iconNode$t = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
177
- const Check = createLucideIcon("check", __iconNode$t);
176
+ const __iconNode$u = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
177
+ const Check = createLucideIcon("check", __iconNode$u);
178
178
  /**
179
179
  * @license lucide-react v0.552.0 - ISC
180
180
  *
181
181
  * This source code is licensed under the ISC license.
182
182
  * See the LICENSE file in the root directory of this source tree.
183
183
  */
184
- const __iconNode$s = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
185
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$s);
184
+ const __iconNode$t = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
185
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$t);
186
186
  /**
187
187
  * @license lucide-react v0.552.0 - ISC
188
188
  *
189
189
  * This source code is licensed under the ISC license.
190
190
  * See the LICENSE file in the root directory of this source tree.
191
191
  */
192
- const __iconNode$r = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
193
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$r);
192
+ const __iconNode$s = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
193
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$s);
194
194
  /**
195
195
  * @license lucide-react v0.552.0 - ISC
196
196
  *
197
197
  * This source code is licensed under the ISC license.
198
198
  * See the LICENSE file in the root directory of this source tree.
199
199
  */
200
- const __iconNode$q = [
200
+ const __iconNode$r = [
201
201
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
202
202
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
203
203
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
204
204
  ];
205
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$q);
205
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$r);
206
206
  /**
207
207
  * @license lucide-react v0.552.0 - ISC
208
208
  *
209
209
  * This source code is licensed under the ISC license.
210
210
  * See the LICENSE file in the root directory of this source tree.
211
211
  */
212
- const __iconNode$p = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
213
- const Circle = createLucideIcon("circle", __iconNode$p);
212
+ const __iconNode$q = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
213
+ const Circle = createLucideIcon("circle", __iconNode$q);
214
214
  /**
215
215
  * @license lucide-react v0.552.0 - ISC
216
216
  *
217
217
  * This source code is licensed under the ISC license.
218
218
  * See the LICENSE file in the root directory of this source tree.
219
219
  */
220
- const __iconNode$o = [
220
+ const __iconNode$p = [
221
221
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
222
222
  ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
223
223
  ];
224
- const Copy = createLucideIcon("copy", __iconNode$o);
224
+ const Copy = createLucideIcon("copy", __iconNode$p);
225
225
  /**
226
226
  * @license lucide-react v0.552.0 - ISC
227
227
  *
228
228
  * This source code is licensed under the ISC license.
229
229
  * See the LICENSE file in the root directory of this source tree.
230
230
  */
231
- const __iconNode$n = [
231
+ const __iconNode$o = [
232
232
  ["path", { d: "M10 12h.01", key: "1kxr2c" }],
233
233
  ["path", { d: "M18 20V6a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v14", key: "36qu9e" }],
234
234
  ["path", { d: "M2 20h20", key: "owomy5" }]
235
235
  ];
236
- const DoorClosed = createLucideIcon("door-closed", __iconNode$n);
236
+ const DoorClosed = createLucideIcon("door-closed", __iconNode$o);
237
237
  /**
238
238
  * @license lucide-react v0.552.0 - ISC
239
239
  *
240
240
  * This source code is licensed under the ISC license.
241
241
  * See the LICENSE file in the root directory of this source tree.
242
242
  */
243
- const __iconNode$m = [
243
+ const __iconNode$n = [
244
244
  ["path", { d: "M12 15V3", key: "m9g1x1" }],
245
245
  ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
246
246
  ["path", { d: "m7 10 5 5 5-5", key: "brsn70" }]
247
247
  ];
248
- const Download = createLucideIcon("download", __iconNode$m);
248
+ const Download = createLucideIcon("download", __iconNode$n);
249
249
  /**
250
250
  * @license lucide-react v0.552.0 - ISC
251
251
  *
252
252
  * This source code is licensed under the ISC license.
253
253
  * See the LICENSE file in the root directory of this source tree.
254
254
  */
255
- const __iconNode$l = [
255
+ const __iconNode$m = [
256
256
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
257
257
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
258
258
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
259
259
  ];
260
- const ExternalLink = createLucideIcon("external-link", __iconNode$l);
260
+ const ExternalLink = createLucideIcon("external-link", __iconNode$m);
261
261
  /**
262
262
  * @license lucide-react v0.552.0 - ISC
263
263
  *
264
264
  * This source code is licensed under the ISC license.
265
265
  * See the LICENSE file in the root directory of this source tree.
266
266
  */
267
- const __iconNode$k = [
267
+ const __iconNode$l = [
268
268
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }],
269
269
  ["path", { d: "M3 7V5a2 2 0 0 1 2-2h2", key: "aa7l1z" }],
270
270
  ["path", { d: "M17 3h2a2 2 0 0 1 2 2v2", key: "4qcy5o" }],
271
271
  ["path", { d: "M21 17v2a2 2 0 0 1-2 2h-2", key: "6vwrx8" }],
272
272
  ["path", { d: "M7 21H5a2 2 0 0 1-2-2v-2", key: "ioqczr" }]
273
273
  ];
274
- const Focus = createLucideIcon("focus", __iconNode$k);
274
+ const Focus = createLucideIcon("focus", __iconNode$l);
275
275
  /**
276
276
  * @license lucide-react v0.552.0 - ISC
277
277
  *
278
278
  * This source code is licensed under the ISC license.
279
279
  * See the LICENSE file in the root directory of this source tree.
280
280
  */
281
- const __iconNode$j = [
281
+ const __iconNode$k = [
282
282
  [
283
283
  "path",
284
284
  {
@@ -290,14 +290,14 @@ const __iconNode$j = [
290
290
  ["path", { d: "M18 19c-2.8 0-5-2.2-5-5v8", key: "pkpw2h" }],
291
291
  ["circle", { cx: "20", cy: "19", r: "2", key: "1obnsp" }]
292
292
  ];
293
- const FolderGit2 = createLucideIcon("folder-git-2", __iconNode$j);
293
+ const FolderGit2 = createLucideIcon("folder-git-2", __iconNode$k);
294
294
  /**
295
295
  * @license lucide-react v0.552.0 - ISC
296
296
  *
297
297
  * This source code is licensed under the ISC license.
298
298
  * See the LICENSE file in the root directory of this source tree.
299
299
  */
300
- const __iconNode$i = [
300
+ const __iconNode$j = [
301
301
  [
302
302
  "path",
303
303
  {
@@ -306,7 +306,25 @@ const __iconNode$i = [
306
306
  }
307
307
  ]
308
308
  ];
309
- const FolderOpen = createLucideIcon("folder-open", __iconNode$i);
309
+ const FolderOpen = createLucideIcon("folder-open", __iconNode$j);
310
+ /**
311
+ * @license lucide-react v0.552.0 - ISC
312
+ *
313
+ * This source code is licensed under the ISC license.
314
+ * See the LICENSE file in the root directory of this source tree.
315
+ */
316
+ const __iconNode$i = [
317
+ ["path", { d: "M12 10v6", key: "1bos4e" }],
318
+ ["path", { d: "M9 13h6", key: "1uhe8q" }],
319
+ [
320
+ "path",
321
+ {
322
+ d: "M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",
323
+ key: "1kt360"
324
+ }
325
+ ]
326
+ ];
327
+ const FolderPlus = createLucideIcon("folder-plus", __iconNode$i);
310
328
  /**
311
329
  * @license lucide-react v0.552.0 - ISC
312
330
  *
@@ -1042,10 +1060,22 @@ const LocalProjectsPanelContent = ({
1042
1060
  var _a;
1043
1061
  const { theme } = useTheme();
1044
1062
  const [filter, setFilter] = useState("");
1063
+ const [showSearch, setShowSearch] = useState(false);
1045
1064
  const [isAdding, setIsAdding] = useState(false);
1046
1065
  const [selectedEntry, setSelectedEntry] = useState(null);
1047
1066
  const [windowStates, setWindowStates] = useState(/* @__PURE__ */ new Map());
1048
1067
  const [sortByOrg, setSortByOrg] = useState(false);
1068
+ const handleToggleSearch = useCallback(() => {
1069
+ setShowSearch((prev) => {
1070
+ if (prev) {
1071
+ setFilter("");
1072
+ }
1073
+ return !prev;
1074
+ });
1075
+ }, []);
1076
+ const handleClearFilter = useCallback(() => {
1077
+ setFilter("");
1078
+ }, []);
1049
1079
  const panelActions = actions;
1050
1080
  const repoSlice = context.getSlice("alexandriaRepositories");
1051
1081
  const repositories = useMemo(
@@ -1226,128 +1256,226 @@ const LocalProjectsPanelContent = ({
1226
1256
  "div",
1227
1257
  {
1228
1258
  style: {
1259
+ position: "relative",
1229
1260
  height: "40px",
1230
1261
  minHeight: "40px",
1231
1262
  padding: "0 16px",
1232
1263
  borderBottom: `1px solid ${theme.colors.border}`,
1233
1264
  display: "flex",
1234
1265
  alignItems: "center",
1235
- gap: "8px"
1266
+ boxSizing: "border-box"
1236
1267
  },
1237
1268
  children: [
1238
- /* @__PURE__ */ jsx(FolderGit2, { size: 18, style: { color: theme.colors.success || "#10b981" } }),
1239
- /* @__PURE__ */ jsx(
1240
- "span",
1269
+ /* @__PURE__ */ jsxs(
1270
+ "div",
1241
1271
  {
1242
1272
  style: {
1243
- fontSize: `${theme.fontSizes[2]}px`,
1244
- fontWeight: theme.fontWeights.medium,
1245
- color: theme.colors.text,
1246
- fontFamily: theme.fonts.body
1273
+ display: "flex",
1274
+ alignItems: "center",
1275
+ justifyContent: "space-between",
1276
+ width: "100%",
1277
+ visibility: showSearch ? "hidden" : "visible"
1247
1278
  },
1248
- children: "Local Projects"
1279
+ children: [
1280
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1281
+ /* @__PURE__ */ jsx(FolderGit2, { size: 18, style: { color: theme.colors.success || "#10b981" } }),
1282
+ /* @__PURE__ */ jsx(
1283
+ "span",
1284
+ {
1285
+ style: {
1286
+ fontSize: `${theme.fontSizes[2]}px`,
1287
+ fontWeight: theme.fontWeights.medium,
1288
+ color: theme.colors.text,
1289
+ fontFamily: theme.fonts.body
1290
+ },
1291
+ children: "Local Projects"
1292
+ }
1293
+ ),
1294
+ repositories.length > 0 && /* @__PURE__ */ jsx(
1295
+ "span",
1296
+ {
1297
+ style: {
1298
+ fontSize: `${theme.fontSizes[1]}px`,
1299
+ color: theme.colors.textSecondary,
1300
+ padding: "2px 8px",
1301
+ borderRadius: "12px",
1302
+ backgroundColor: theme.colors.background
1303
+ },
1304
+ children: repositories.length
1305
+ }
1306
+ )
1307
+ ] }),
1308
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1309
+ /* @__PURE__ */ jsx(
1310
+ "button",
1311
+ {
1312
+ className: `header-button ${showSearch ? "active" : ""}`,
1313
+ onClick: handleToggleSearch,
1314
+ style: {
1315
+ background: showSearch ? theme.colors.backgroundSecondary : "none",
1316
+ border: `1px solid ${showSearch ? theme.colors.border : "transparent"}`,
1317
+ borderRadius: "4px",
1318
+ cursor: "pointer",
1319
+ padding: "4px",
1320
+ display: "flex",
1321
+ alignItems: "center",
1322
+ justifyContent: "center",
1323
+ color: showSearch ? theme.colors.primary : theme.colors.textSecondary,
1324
+ ["--theme-text"]: theme.colors.text
1325
+ },
1326
+ title: showSearch ? "Close search" : "Search projects",
1327
+ children: /* @__PURE__ */ jsx(Search, { size: 16 })
1328
+ }
1329
+ ),
1330
+ /* @__PURE__ */ jsx(
1331
+ "button",
1332
+ {
1333
+ onClick: () => setSortByOrg(!sortByOrg),
1334
+ title: sortByOrg ? "Sorting by organization" : "Sorting by repo name",
1335
+ style: {
1336
+ padding: "4px",
1337
+ borderRadius: "4px",
1338
+ border: `1px solid ${sortByOrg ? theme.colors.border : "transparent"}`,
1339
+ backgroundColor: sortByOrg ? theme.colors.backgroundSecondary : "none",
1340
+ color: sortByOrg ? theme.colors.primary : theme.colors.textSecondary,
1341
+ cursor: "pointer",
1342
+ display: "flex",
1343
+ alignItems: "center",
1344
+ justifyContent: "center",
1345
+ transition: "all 0.15s",
1346
+ flexShrink: 0
1347
+ },
1348
+ children: sortByOrg ? /* @__PURE__ */ jsx(Building2, { size: 16 }) : /* @__PURE__ */ jsx(FolderGit2, { size: 16 })
1349
+ }
1350
+ ),
1351
+ panelActions.selectDirectory && /* @__PURE__ */ jsx(
1352
+ "button",
1353
+ {
1354
+ onClick: handleAddProject,
1355
+ disabled: isAdding,
1356
+ title: "Add existing project",
1357
+ style: {
1358
+ padding: "4px",
1359
+ borderRadius: "4px",
1360
+ border: "none",
1361
+ backgroundColor: theme.colors.primary,
1362
+ color: theme.colors.background,
1363
+ cursor: isAdding ? "default" : "pointer",
1364
+ display: "flex",
1365
+ alignItems: "center",
1366
+ justifyContent: "center",
1367
+ opacity: isAdding ? 0.6 : 1,
1368
+ transition: "opacity 0.2s",
1369
+ flexShrink: 0
1370
+ },
1371
+ children: /* @__PURE__ */ jsx(Plus, { size: 16 })
1372
+ }
1373
+ )
1374
+ ] })
1375
+ ]
1249
1376
  }
1250
1377
  ),
1251
- repositories.length > 0 && /* @__PURE__ */ jsx(
1252
- "span",
1378
+ showSearch && /* @__PURE__ */ jsxs(
1379
+ "div",
1253
1380
  {
1381
+ className: "search-overlay",
1254
1382
  style: {
1255
- fontSize: `${theme.fontSizes[1]}px`,
1256
- color: theme.colors.textSecondary,
1257
- padding: "2px 8px",
1258
- borderRadius: "12px",
1259
- backgroundColor: theme.colors.background
1383
+ position: "absolute",
1384
+ top: 0,
1385
+ left: 0,
1386
+ right: 0,
1387
+ bottom: 0,
1388
+ display: "flex",
1389
+ alignItems: "center",
1390
+ padding: "0 16px",
1391
+ backgroundColor: theme.colors.backgroundSecondary,
1392
+ zIndex: 10
1260
1393
  },
1261
- children: repositories.length
1394
+ children: [
1395
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flex: 1, display: "flex", alignItems: "center" }, children: [
1396
+ /* @__PURE__ */ jsx(
1397
+ Search,
1398
+ {
1399
+ size: 16,
1400
+ color: theme.colors.textSecondary,
1401
+ style: {
1402
+ position: "absolute",
1403
+ left: "10px",
1404
+ pointerEvents: "none"
1405
+ }
1406
+ }
1407
+ ),
1408
+ /* @__PURE__ */ jsx(
1409
+ "input",
1410
+ {
1411
+ type: "text",
1412
+ className: "search-input",
1413
+ placeholder: "Filter local projects...",
1414
+ value: filter,
1415
+ onChange: (e) => setFilter(e.target.value),
1416
+ autoFocus: true,
1417
+ style: {
1418
+ width: "100%",
1419
+ padding: "6px 32px 6px 32px",
1420
+ fontSize: `${theme.fontSizes[1]}px`,
1421
+ color: theme.colors.text,
1422
+ backgroundColor: theme.colors.background,
1423
+ border: `1px solid ${theme.colors.border}`,
1424
+ borderRadius: "4px",
1425
+ outline: "none",
1426
+ fontFamily: theme.fonts.body,
1427
+ transition: "border-color 0.2s ease",
1428
+ ["--theme-primary"]: theme.colors.primary
1429
+ }
1430
+ }
1431
+ ),
1432
+ filter && /* @__PURE__ */ jsx(
1433
+ "button",
1434
+ {
1435
+ className: "clear-filter-button",
1436
+ onClick: handleClearFilter,
1437
+ style: {
1438
+ position: "absolute",
1439
+ right: "8px",
1440
+ background: "none",
1441
+ border: "none",
1442
+ cursor: "pointer",
1443
+ padding: "4px",
1444
+ display: "flex",
1445
+ alignItems: "center",
1446
+ justifyContent: "center",
1447
+ color: theme.colors.textSecondary,
1448
+ ["--theme-text"]: theme.colors.text
1449
+ },
1450
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
1451
+ }
1452
+ )
1453
+ ] }),
1454
+ /* @__PURE__ */ jsx(
1455
+ "button",
1456
+ {
1457
+ onClick: handleToggleSearch,
1458
+ style: {
1459
+ background: "none",
1460
+ border: "none",
1461
+ cursor: "pointer",
1462
+ padding: "4px",
1463
+ marginLeft: "8px",
1464
+ display: "flex",
1465
+ alignItems: "center",
1466
+ justifyContent: "center",
1467
+ color: theme.colors.textSecondary
1468
+ },
1469
+ title: "Close search",
1470
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
1471
+ }
1472
+ )
1473
+ ]
1262
1474
  }
1263
- ),
1264
- /* @__PURE__ */ jsxs("div", { style: { marginLeft: "auto", display: "flex", gap: "8px" }, children: [
1265
- /* @__PURE__ */ jsx(
1266
- "button",
1267
- {
1268
- onClick: () => setSortByOrg(!sortByOrg),
1269
- title: sortByOrg ? "Sorting by organization" : "Sorting by repo name",
1270
- style: {
1271
- padding: "6px",
1272
- borderRadius: "6px",
1273
- border: `1px solid ${theme.colors.border}`,
1274
- backgroundColor: sortByOrg ? `${theme.colors.primary}20` : theme.colors.background,
1275
- color: sortByOrg ? theme.colors.primary : theme.colors.textSecondary,
1276
- cursor: "pointer",
1277
- display: "flex",
1278
- alignItems: "center",
1279
- justifyContent: "center",
1280
- transition: "all 0.15s",
1281
- flexShrink: 0
1282
- },
1283
- children: sortByOrg ? /* @__PURE__ */ jsx(Building2, { size: 16 }) : /* @__PURE__ */ jsx(FolderGit2, { size: 16 })
1284
- }
1285
- ),
1286
- panelActions.selectDirectory && /* @__PURE__ */ jsx(
1287
- "button",
1288
- {
1289
- onClick: handleAddProject,
1290
- disabled: isAdding,
1291
- title: "Add existing project",
1292
- style: {
1293
- padding: "6px",
1294
- borderRadius: "6px",
1295
- border: `1px solid ${theme.colors.border}`,
1296
- backgroundColor: theme.colors.primary,
1297
- color: theme.colors.background,
1298
- cursor: isAdding ? "default" : "pointer",
1299
- display: "flex",
1300
- alignItems: "center",
1301
- justifyContent: "center",
1302
- opacity: isAdding ? 0.6 : 1,
1303
- transition: "opacity 0.2s",
1304
- flexShrink: 0
1305
- },
1306
- children: /* @__PURE__ */ jsx(Plus, { size: 16 })
1307
- }
1308
- )
1309
- ] })
1475
+ )
1310
1476
  ]
1311
1477
  }
1312
1478
  ),
1313
- /* @__PURE__ */ jsx("div", { style: { padding: "8px 16px" }, children: /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
1314
- /* @__PURE__ */ jsx(
1315
- Search,
1316
- {
1317
- size: 16,
1318
- style: {
1319
- position: "absolute",
1320
- top: "50%",
1321
- left: "12px",
1322
- transform: "translateY(-50%)",
1323
- color: theme.colors.textSecondary,
1324
- pointerEvents: "none",
1325
- zIndex: 1
1326
- }
1327
- }
1328
- ),
1329
- /* @__PURE__ */ jsx(
1330
- "input",
1331
- {
1332
- type: "text",
1333
- value: filter,
1334
- placeholder: "Filter local projects...",
1335
- onChange: (event) => setFilter(event.target.value),
1336
- style: {
1337
- width: "100%",
1338
- boxSizing: "border-box",
1339
- padding: "8px 12px 8px 36px",
1340
- borderRadius: "6px",
1341
- border: `1px solid ${theme.colors.border}`,
1342
- backgroundColor: theme.colors.background,
1343
- color: theme.colors.text,
1344
- fontSize: `${theme.fontSizes[1]}px`,
1345
- fontFamily: theme.fonts.body,
1346
- outline: "none"
1347
- }
1348
- }
1349
- )
1350
- ] }) }),
1351
1479
  /* @__PURE__ */ jsxs(
1352
1480
  "div",
1353
1481
  {
@@ -3015,6 +3143,19 @@ const WorkspaceCollectionPanelContent = ({
3015
3143
  const { theme } = useTheme();
3016
3144
  const [selectedRepo, setSelectedRepo] = useState(null);
3017
3145
  const [sortField, setSortField] = useState("name");
3146
+ const [filter, setFilter] = useState("");
3147
+ const [showSearch, setShowSearch] = useState(false);
3148
+ const handleToggleSearch = useCallback(() => {
3149
+ setShowSearch((prev) => {
3150
+ if (prev) {
3151
+ setFilter("");
3152
+ }
3153
+ return !prev;
3154
+ });
3155
+ }, []);
3156
+ const handleClearFilter = useCallback(() => {
3157
+ setFilter("");
3158
+ }, []);
3018
3159
  const panelActions = actions;
3019
3160
  const workspaceSlice = context.getSlice("workspace");
3020
3161
  const repositoriesSlice = context.getSlice("workspaceRepositories");
@@ -3049,8 +3190,23 @@ const WorkspaceCollectionPanelContent = ({
3049
3190
  const toggleSort = () => {
3050
3191
  setSortField(sortField === "name" ? "updated" : "name");
3051
3192
  };
3052
- const sortedRepositories = useMemo(() => {
3053
- return [...repositories].sort((a, b) => {
3193
+ const normalizedFilter = filter.trim().toLowerCase();
3194
+ const filteredAndSortedRepositories = useMemo(() => {
3195
+ let filtered = repositories;
3196
+ if (normalizedFilter) {
3197
+ filtered = repositories.filter((repo) => {
3198
+ var _a2;
3199
+ const haystack = [
3200
+ repo.name,
3201
+ repo.full_name,
3202
+ ((_a2 = repo.owner) == null ? void 0 : _a2.login) ?? "",
3203
+ repo.description ?? "",
3204
+ repo.language ?? ""
3205
+ ].join(" ").toLowerCase();
3206
+ return haystack.includes(normalizedFilter);
3207
+ });
3208
+ }
3209
+ return [...filtered].sort((a, b) => {
3054
3210
  if (sortField === "name") {
3055
3211
  return a.name.localeCompare(b.name);
3056
3212
  } else {
@@ -3059,7 +3215,7 @@ const WorkspaceCollectionPanelContent = ({
3059
3215
  return bTime - aTime;
3060
3216
  }
3061
3217
  });
3062
- }, [repositories, sortField]);
3218
+ }, [repositories, sortField, normalizedFilter]);
3063
3219
  const handleSelectRepository = useCallback(
3064
3220
  (repository) => {
3065
3221
  setSelectedRepo(repository);
@@ -3280,64 +3436,199 @@ const WorkspaceCollectionPanelContent = ({
3280
3436
  "div",
3281
3437
  {
3282
3438
  style: {
3439
+ position: "relative",
3283
3440
  height: "40px",
3284
3441
  minHeight: "40px",
3285
3442
  padding: "0 16px",
3286
3443
  borderBottom: `1px solid ${theme.colors.border}`,
3287
3444
  display: "flex",
3288
3445
  alignItems: "center",
3289
- gap: "8px"
3446
+ boxSizing: "border-box"
3290
3447
  },
3291
3448
  children: [
3292
- /* @__PURE__ */ jsx(Folder, { size: 18, color: theme.colors.primary }),
3293
- /* @__PURE__ */ jsx(
3294
- "span",
3449
+ /* @__PURE__ */ jsxs(
3450
+ "div",
3295
3451
  {
3296
3452
  style: {
3297
- fontSize: `${theme.fontSizes[2]}px`,
3298
- fontWeight: theme.fontWeights.medium,
3299
- color: theme.colors.text,
3300
- fontFamily: theme.fonts.body
3453
+ display: "flex",
3454
+ alignItems: "center",
3455
+ justifyContent: "space-between",
3456
+ width: "100%",
3457
+ visibility: showSearch ? "hidden" : "visible"
3301
3458
  },
3302
- children: "Repositories"
3459
+ children: [
3460
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
3461
+ /* @__PURE__ */ jsx(Folder, { size: 18, color: theme.colors.primary }),
3462
+ /* @__PURE__ */ jsx(
3463
+ "span",
3464
+ {
3465
+ style: {
3466
+ fontSize: `${theme.fontSizes[2]}px`,
3467
+ fontWeight: theme.fontWeights.medium,
3468
+ color: theme.colors.text,
3469
+ fontFamily: theme.fonts.body
3470
+ },
3471
+ children: "Repositories"
3472
+ }
3473
+ ),
3474
+ repositories.length > 0 && /* @__PURE__ */ jsx(
3475
+ "span",
3476
+ {
3477
+ style: {
3478
+ fontSize: `${theme.fontSizes[1]}px`,
3479
+ color: theme.colors.textSecondary,
3480
+ padding: "2px 8px",
3481
+ borderRadius: "12px",
3482
+ backgroundColor: theme.colors.background
3483
+ },
3484
+ children: repositories.length
3485
+ }
3486
+ )
3487
+ ] }),
3488
+ repositories.length > 0 && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
3489
+ /* @__PURE__ */ jsx(
3490
+ "button",
3491
+ {
3492
+ className: `header-button ${showSearch ? "active" : ""}`,
3493
+ onClick: handleToggleSearch,
3494
+ style: {
3495
+ background: showSearch ? theme.colors.backgroundSecondary : "none",
3496
+ border: `1px solid ${showSearch ? theme.colors.border : "transparent"}`,
3497
+ borderRadius: "4px",
3498
+ cursor: "pointer",
3499
+ padding: "4px",
3500
+ display: "flex",
3501
+ alignItems: "center",
3502
+ justifyContent: "center",
3503
+ color: showSearch ? theme.colors.primary : theme.colors.textSecondary,
3504
+ ["--theme-text"]: theme.colors.text
3505
+ },
3506
+ title: showSearch ? "Close search" : "Search repositories",
3507
+ children: /* @__PURE__ */ jsx(Search, { size: 16 })
3508
+ }
3509
+ ),
3510
+ /* @__PURE__ */ jsx(
3511
+ "button",
3512
+ {
3513
+ onClick: toggleSort,
3514
+ style: {
3515
+ padding: "4px 10px",
3516
+ borderRadius: "4px",
3517
+ border: `1px solid ${theme.colors.border}`,
3518
+ background: theme.colors.background,
3519
+ color: theme.colors.text,
3520
+ fontSize: `${theme.fontSizes[1]}px`,
3521
+ fontFamily: theme.fonts.body,
3522
+ cursor: "pointer",
3523
+ display: "flex",
3524
+ alignItems: "center",
3525
+ gap: "4px"
3526
+ },
3527
+ children: sortField === "name" ? "A-Z" : "Recent"
3528
+ }
3529
+ )
3530
+ ] })
3531
+ ]
3303
3532
  }
3304
3533
  ),
3305
- repositories.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
3306
- /* @__PURE__ */ jsx(
3307
- "span",
3308
- {
3309
- style: {
3310
- fontSize: `${theme.fontSizes[1]}px`,
3311
- color: theme.colors.textSecondary,
3312
- padding: "2px 8px",
3313
- borderRadius: "12px",
3314
- backgroundColor: theme.colors.background
3315
- },
3316
- children: repositories.length
3317
- }
3318
- ),
3319
- /* @__PURE__ */ jsx(
3320
- "button",
3321
- {
3322
- onClick: toggleSort,
3323
- style: {
3324
- marginLeft: "auto",
3325
- padding: "4px 10px",
3326
- borderRadius: "4px",
3327
- border: `1px solid ${theme.colors.border}`,
3328
- background: theme.colors.background,
3329
- color: theme.colors.text,
3330
- fontSize: `${theme.fontSizes[1]}px`,
3331
- fontFamily: theme.fonts.body,
3332
- cursor: "pointer",
3333
- display: "flex",
3334
- alignItems: "center",
3335
- gap: "4px"
3336
- },
3337
- children: sortField === "name" ? "A-Z" : "Recent"
3338
- }
3339
- )
3340
- ] })
3534
+ showSearch && /* @__PURE__ */ jsxs(
3535
+ "div",
3536
+ {
3537
+ className: "search-overlay",
3538
+ style: {
3539
+ position: "absolute",
3540
+ top: 0,
3541
+ left: 0,
3542
+ right: 0,
3543
+ bottom: 0,
3544
+ display: "flex",
3545
+ alignItems: "center",
3546
+ padding: "0 16px",
3547
+ backgroundColor: theme.colors.backgroundSecondary,
3548
+ zIndex: 10
3549
+ },
3550
+ children: [
3551
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flex: 1, display: "flex", alignItems: "center" }, children: [
3552
+ /* @__PURE__ */ jsx(
3553
+ Search,
3554
+ {
3555
+ size: 16,
3556
+ color: theme.colors.textSecondary,
3557
+ style: {
3558
+ position: "absolute",
3559
+ left: "10px",
3560
+ pointerEvents: "none"
3561
+ }
3562
+ }
3563
+ ),
3564
+ /* @__PURE__ */ jsx(
3565
+ "input",
3566
+ {
3567
+ type: "text",
3568
+ className: "search-input",
3569
+ placeholder: "Filter repositories...",
3570
+ value: filter,
3571
+ onChange: (e) => setFilter(e.target.value),
3572
+ autoFocus: true,
3573
+ style: {
3574
+ width: "100%",
3575
+ padding: "6px 32px 6px 32px",
3576
+ fontSize: `${theme.fontSizes[1]}px`,
3577
+ color: theme.colors.text,
3578
+ backgroundColor: theme.colors.background,
3579
+ border: `1px solid ${theme.colors.border}`,
3580
+ borderRadius: "4px",
3581
+ outline: "none",
3582
+ fontFamily: theme.fonts.body,
3583
+ transition: "border-color 0.2s ease",
3584
+ ["--theme-primary"]: theme.colors.primary
3585
+ }
3586
+ }
3587
+ ),
3588
+ filter && /* @__PURE__ */ jsx(
3589
+ "button",
3590
+ {
3591
+ className: "clear-filter-button",
3592
+ onClick: handleClearFilter,
3593
+ style: {
3594
+ position: "absolute",
3595
+ right: "8px",
3596
+ background: "none",
3597
+ border: "none",
3598
+ cursor: "pointer",
3599
+ padding: "4px",
3600
+ display: "flex",
3601
+ alignItems: "center",
3602
+ justifyContent: "center",
3603
+ color: theme.colors.textSecondary,
3604
+ ["--theme-text"]: theme.colors.text
3605
+ },
3606
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
3607
+ }
3608
+ )
3609
+ ] }),
3610
+ /* @__PURE__ */ jsx(
3611
+ "button",
3612
+ {
3613
+ onClick: handleToggleSearch,
3614
+ style: {
3615
+ background: "none",
3616
+ border: "none",
3617
+ cursor: "pointer",
3618
+ padding: "4px",
3619
+ marginLeft: "8px",
3620
+ display: "flex",
3621
+ alignItems: "center",
3622
+ justifyContent: "center",
3623
+ color: theme.colors.textSecondary
3624
+ },
3625
+ title: "Close search",
3626
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
3627
+ }
3628
+ )
3629
+ ]
3630
+ }
3631
+ )
3341
3632
  ]
3342
3633
  }
3343
3634
  ),
@@ -3399,7 +3690,18 @@ const WorkspaceCollectionPanelContent = ({
3399
3690
  ]
3400
3691
  }
3401
3692
  ),
3402
- sortedRepositories.map((repository) => /* @__PURE__ */ jsx(
3693
+ filteredAndSortedRepositories.length === 0 && repositories.length > 0 && /* @__PURE__ */ jsx(
3694
+ "div",
3695
+ {
3696
+ style: {
3697
+ padding: "32px",
3698
+ textAlign: "center",
3699
+ color: theme.colors.textSecondary
3700
+ },
3701
+ children: /* @__PURE__ */ jsx("p", { style: { margin: 0 }, children: "No repositories match your filter." })
3702
+ }
3703
+ ),
3704
+ filteredAndSortedRepositories.map((repository) => /* @__PURE__ */ jsx(
3403
3705
  WorkspaceCollectionRepositoryCard,
3404
3706
  {
3405
3707
  repository,
@@ -3471,7 +3773,10 @@ const GitHubRepositoryCard = ({
3471
3773
  onOpen,
3472
3774
  isLoading = false,
3473
3775
  isSelected = false,
3474
- onSelect
3776
+ onSelect,
3777
+ onAddToCollection,
3778
+ isInCollection = false,
3779
+ collectionName
3475
3780
  }) => {
3476
3781
  const { theme } = useTheme();
3477
3782
  const [isHovered, setIsHovered] = useState(false);
@@ -3506,6 +3811,15 @@ const GitHubRepositoryCard = ({
3506
3811
  },
3507
3812
  [repository.html_url]
3508
3813
  );
3814
+ const handleAddToCollection = useCallback(
3815
+ (e) => {
3816
+ e.stopPropagation();
3817
+ if (onAddToCollection && !isLoading && !isInCollection) {
3818
+ onAddToCollection(repository);
3819
+ }
3820
+ },
3821
+ [onAddToCollection, repository, isLoading, isInCollection]
3822
+ );
3509
3823
  const getRelativeTime = (dateString) => {
3510
3824
  const date = new Date(dateString);
3511
3825
  const now = /* @__PURE__ */ new Date();
@@ -3700,12 +4014,41 @@ const GitHubRepositoryCard = ({
3700
4014
  children: /* @__PURE__ */ jsx(ExternalLink, { size: 16 })
3701
4015
  }
3702
4016
  ),
3703
- isCloned ? /* @__PURE__ */ jsxs(
4017
+ onAddToCollection && /* @__PURE__ */ jsxs(
4018
+ "button",
4019
+ {
4020
+ type: "button",
4021
+ onClick: handleAddToCollection,
4022
+ disabled: isLoading || isInCollection,
4023
+ style: {
4024
+ display: "flex",
4025
+ alignItems: "center",
4026
+ gap: "6px",
4027
+ padding: "6px 12px",
4028
+ borderRadius: "6px",
4029
+ border: "none",
4030
+ backgroundColor: isInCollection ? "#10b981" : theme.colors.secondary,
4031
+ color: isInCollection ? "#ffffff" : theme.colors.text,
4032
+ fontSize: `${theme.fontSizes[1]}px`,
4033
+ fontWeight: theme.fontWeights.medium,
4034
+ fontFamily: theme.fonts.body,
4035
+ cursor: isLoading || isInCollection ? "not-allowed" : "pointer",
4036
+ opacity: isLoading ? 0.6 : 1,
4037
+ transition: "opacity 0.15s, background-color 0.15s"
4038
+ },
4039
+ title: isInCollection ? `Already in ${collectionName || "collection"}` : `Add to ${collectionName || "collection"}`,
4040
+ children: [
4041
+ isInCollection ? /* @__PURE__ */ jsx(Check, { size: 14 }) : /* @__PURE__ */ jsx(FolderPlus, { size: 14 }),
4042
+ isInCollection ? "Added" : "Add"
4043
+ ]
4044
+ }
4045
+ ),
4046
+ isCloned && onOpen && /* @__PURE__ */ jsxs(
3704
4047
  "button",
3705
4048
  {
3706
4049
  type: "button",
3707
4050
  onClick: handleOpen,
3708
- disabled: isLoading || !onOpen,
4051
+ disabled: isLoading,
3709
4052
  style: {
3710
4053
  display: "flex",
3711
4054
  alignItems: "center",
@@ -3718,8 +4061,8 @@ const GitHubRepositoryCard = ({
3718
4061
  fontSize: `${theme.fontSizes[1]}px`,
3719
4062
  fontWeight: theme.fontWeights.medium,
3720
4063
  fontFamily: theme.fonts.body,
3721
- cursor: isLoading || !onOpen ? "not-allowed" : "pointer",
3722
- opacity: isLoading || !onOpen ? 0.6 : 1,
4064
+ cursor: isLoading ? "not-allowed" : "pointer",
4065
+ opacity: isLoading ? 0.6 : 1,
3723
4066
  transition: "opacity 0.15s"
3724
4067
  },
3725
4068
  title: "Open in workspace",
@@ -3728,12 +4071,13 @@ const GitHubRepositoryCard = ({
3728
4071
  "Open"
3729
4072
  ]
3730
4073
  }
3731
- ) : /* @__PURE__ */ jsxs(
4074
+ ),
4075
+ !isCloned && onClone && /* @__PURE__ */ jsxs(
3732
4076
  "button",
3733
4077
  {
3734
4078
  type: "button",
3735
4079
  onClick: handleClone,
3736
- disabled: isLoading || !onClone,
4080
+ disabled: isLoading,
3737
4081
  style: {
3738
4082
  display: "flex",
3739
4083
  alignItems: "center",
@@ -3746,8 +4090,8 @@ const GitHubRepositoryCard = ({
3746
4090
  fontSize: `${theme.fontSizes[1]}px`,
3747
4091
  fontWeight: theme.fontWeights.medium,
3748
4092
  fontFamily: theme.fonts.body,
3749
- cursor: isLoading || !onClone ? "not-allowed" : "pointer",
3750
- opacity: isLoading || !onClone ? 0.6 : 1,
4093
+ cursor: isLoading ? "not-allowed" : "pointer",
4094
+ opacity: isLoading ? 0.6 : 1,
3751
4095
  transition: "opacity 0.15s"
3752
4096
  },
3753
4097
  title: "Clone repository",
@@ -3809,14 +4153,29 @@ const GitHubStarredPanel = (props) => {
3809
4153
  const GitHubStarredPanelContent = ({
3810
4154
  context,
3811
4155
  actions,
3812
- events
4156
+ events,
4157
+ defaultShowSearch = false
3813
4158
  }) => {
3814
- var _a, _b, _c;
4159
+ var _a, _b, _c, _d, _e;
3815
4160
  const { theme } = useTheme();
3816
4161
  const [filter, setFilter] = useState("");
4162
+ const [showSearch, setShowSearch] = useState(defaultShowSearch);
3817
4163
  const [selectedRepo, setSelectedRepo] = useState(null);
4164
+ const handleToggleSearch = useCallback(() => {
4165
+ setShowSearch((prev) => {
4166
+ if (prev) {
4167
+ setFilter("");
4168
+ }
4169
+ return !prev;
4170
+ });
4171
+ }, []);
4172
+ const handleClearFilter = useCallback(() => {
4173
+ setFilter("");
4174
+ }, []);
3818
4175
  const starredSlice = context.getSlice("githubStarred");
3819
4176
  const localReposSlice = context.getSlice("alexandriaRepositories");
4177
+ const workspaceSlice = context.getSlice("workspace");
4178
+ const workspaceReposSlice = context.getSlice("workspaceRepositories");
3820
4179
  const repositories = useMemo(
3821
4180
  () => {
3822
4181
  var _a2;
@@ -3833,6 +4192,18 @@ const GitHubStarredPanelContent = ({
3833
4192
  },
3834
4193
  [(_c = localReposSlice == null ? void 0 : localReposSlice.data) == null ? void 0 : _c.repositories]
3835
4194
  );
4195
+ const currentWorkspace = (_d = workspaceSlice == null ? void 0 : workspaceSlice.data) == null ? void 0 : _d.workspace;
4196
+ const collectionName = currentWorkspace == null ? void 0 : currentWorkspace.name;
4197
+ const collectionRepos = useMemo(
4198
+ () => {
4199
+ var _a2;
4200
+ return ((_a2 = workspaceReposSlice == null ? void 0 : workspaceReposSlice.data) == null ? void 0 : _a2.repositories) || [];
4201
+ },
4202
+ [(_e = workspaceReposSlice == null ? void 0 : workspaceReposSlice.data) == null ? void 0 : _e.repositories]
4203
+ );
4204
+ const collectionRepoSet = useMemo(() => {
4205
+ return new Set(collectionRepos.map((r) => r.full_name));
4206
+ }, [collectionRepos]);
3836
4207
  const panelActions = actions;
3837
4208
  const localRepoMap = useMemo(() => {
3838
4209
  const map = /* @__PURE__ */ new Map();
@@ -3918,6 +4289,19 @@ const GitHubStarredPanelContent = ({
3918
4289
  await panelActions.refreshStarred();
3919
4290
  }
3920
4291
  }, [panelActions]);
4292
+ const handleAddToCollection = useCallback(
4293
+ async (repo) => {
4294
+ if (panelActions.addToCollection) {
4295
+ await panelActions.addToCollection(repo);
4296
+ events.emit(
4297
+ createPanelEvent$2(`${PANEL_ID$9}:repository-added-to-collection`, {
4298
+ repository: repo
4299
+ })
4300
+ );
4301
+ }
4302
+ },
4303
+ [panelActions, events]
4304
+ );
3921
4305
  useEffect(() => {
3922
4306
  const unsubscribers = [
3923
4307
  events.on(`${PANEL_ID$9}:filter`, (event) => {
@@ -4102,81 +4486,180 @@ const GitHubStarredPanelContent = ({
4102
4486
  "div",
4103
4487
  {
4104
4488
  style: {
4489
+ position: "relative",
4105
4490
  height: "40px",
4106
4491
  minHeight: "40px",
4107
4492
  padding: "0 16px",
4108
4493
  borderBottom: `1px solid ${theme.colors.border}`,
4109
4494
  display: "flex",
4110
4495
  alignItems: "center",
4111
- gap: "8px"
4496
+ boxSizing: "border-box"
4112
4497
  },
4113
4498
  children: [
4114
- /* @__PURE__ */ jsx(Star, { size: 18, style: { color: "#f59e0b" } }),
4115
- /* @__PURE__ */ jsx(
4116
- "span",
4499
+ /* @__PURE__ */ jsxs(
4500
+ "div",
4117
4501
  {
4118
4502
  style: {
4119
- fontSize: `${theme.fontSizes[2]}px`,
4120
- fontWeight: theme.fontWeights.medium,
4121
- color: theme.colors.text,
4122
- fontFamily: theme.fonts.body
4503
+ display: "flex",
4504
+ alignItems: "center",
4505
+ justifyContent: "space-between",
4506
+ width: "100%",
4507
+ visibility: showSearch ? "hidden" : "visible"
4123
4508
  },
4124
- children: "Starred"
4509
+ children: [
4510
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
4511
+ /* @__PURE__ */ jsx(Star, { size: 18, style: { color: "#f59e0b" } }),
4512
+ /* @__PURE__ */ jsx(
4513
+ "span",
4514
+ {
4515
+ style: {
4516
+ fontSize: `${theme.fontSizes[2]}px`,
4517
+ fontWeight: theme.fontWeights.medium,
4518
+ color: theme.colors.text,
4519
+ fontFamily: theme.fonts.body
4520
+ },
4521
+ children: "Starred"
4522
+ }
4523
+ ),
4524
+ repositories.length > 0 && /* @__PURE__ */ jsx(
4525
+ "span",
4526
+ {
4527
+ style: {
4528
+ fontSize: `${theme.fontSizes[1]}px`,
4529
+ color: theme.colors.textSecondary,
4530
+ padding: "2px 8px",
4531
+ borderRadius: "12px",
4532
+ backgroundColor: theme.colors.background
4533
+ },
4534
+ children: repositories.length
4535
+ }
4536
+ )
4537
+ ] }),
4538
+ /* @__PURE__ */ jsx(
4539
+ "button",
4540
+ {
4541
+ className: `header-button ${showSearch ? "active" : ""}`,
4542
+ onClick: handleToggleSearch,
4543
+ style: {
4544
+ background: showSearch ? theme.colors.backgroundSecondary : "none",
4545
+ border: `1px solid ${showSearch ? theme.colors.border : "transparent"}`,
4546
+ borderRadius: "4px",
4547
+ cursor: "pointer",
4548
+ padding: "4px",
4549
+ display: "flex",
4550
+ alignItems: "center",
4551
+ justifyContent: "center",
4552
+ color: showSearch ? theme.colors.primary : theme.colors.textSecondary,
4553
+ ["--theme-text"]: theme.colors.text
4554
+ },
4555
+ title: showSearch ? "Close search" : "Search repositories",
4556
+ children: /* @__PURE__ */ jsx(Search, { size: 16 })
4557
+ }
4558
+ )
4559
+ ]
4125
4560
  }
4126
4561
  ),
4127
- repositories.length > 0 && /* @__PURE__ */ jsx(
4128
- "span",
4562
+ showSearch && /* @__PURE__ */ jsxs(
4563
+ "div",
4129
4564
  {
4565
+ className: "search-overlay",
4130
4566
  style: {
4131
- fontSize: `${theme.fontSizes[1]}px`,
4132
- color: theme.colors.textSecondary,
4133
- padding: "2px 8px",
4134
- borderRadius: "12px",
4135
- backgroundColor: theme.colors.background
4567
+ position: "absolute",
4568
+ top: 0,
4569
+ left: 0,
4570
+ right: 0,
4571
+ bottom: 0,
4572
+ display: "flex",
4573
+ alignItems: "center",
4574
+ padding: "0 16px",
4575
+ backgroundColor: theme.colors.backgroundSecondary,
4576
+ zIndex: 10
4136
4577
  },
4137
- children: repositories.length
4578
+ children: [
4579
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flex: 1, display: "flex", alignItems: "center" }, children: [
4580
+ /* @__PURE__ */ jsx(
4581
+ Search,
4582
+ {
4583
+ size: 16,
4584
+ color: theme.colors.textSecondary,
4585
+ style: {
4586
+ position: "absolute",
4587
+ left: "10px",
4588
+ pointerEvents: "none"
4589
+ }
4590
+ }
4591
+ ),
4592
+ /* @__PURE__ */ jsx(
4593
+ "input",
4594
+ {
4595
+ type: "text",
4596
+ className: "search-input",
4597
+ placeholder: "Filter starred repositories...",
4598
+ value: filter,
4599
+ onChange: (e) => setFilter(e.target.value),
4600
+ autoFocus: true,
4601
+ style: {
4602
+ width: "100%",
4603
+ padding: "6px 32px 6px 32px",
4604
+ fontSize: `${theme.fontSizes[1]}px`,
4605
+ color: theme.colors.text,
4606
+ backgroundColor: theme.colors.background,
4607
+ border: `1px solid ${theme.colors.border}`,
4608
+ borderRadius: "4px",
4609
+ outline: "none",
4610
+ fontFamily: theme.fonts.body,
4611
+ transition: "border-color 0.2s ease",
4612
+ ["--theme-primary"]: theme.colors.primary
4613
+ }
4614
+ }
4615
+ ),
4616
+ filter && /* @__PURE__ */ jsx(
4617
+ "button",
4618
+ {
4619
+ className: "clear-filter-button",
4620
+ onClick: handleClearFilter,
4621
+ style: {
4622
+ position: "absolute",
4623
+ right: "8px",
4624
+ background: "none",
4625
+ border: "none",
4626
+ cursor: "pointer",
4627
+ padding: "4px",
4628
+ display: "flex",
4629
+ alignItems: "center",
4630
+ justifyContent: "center",
4631
+ color: theme.colors.textSecondary,
4632
+ ["--theme-text"]: theme.colors.text
4633
+ },
4634
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
4635
+ }
4636
+ )
4637
+ ] }),
4638
+ /* @__PURE__ */ jsx(
4639
+ "button",
4640
+ {
4641
+ onClick: handleToggleSearch,
4642
+ style: {
4643
+ background: "none",
4644
+ border: "none",
4645
+ cursor: "pointer",
4646
+ padding: "4px",
4647
+ marginLeft: "8px",
4648
+ display: "flex",
4649
+ alignItems: "center",
4650
+ justifyContent: "center",
4651
+ color: theme.colors.textSecondary
4652
+ },
4653
+ title: "Close search",
4654
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
4655
+ }
4656
+ )
4657
+ ]
4138
4658
  }
4139
4659
  )
4140
4660
  ]
4141
4661
  }
4142
4662
  ),
4143
- /* @__PURE__ */ jsxs("div", { style: { position: "relative", padding: "8px 16px" }, children: [
4144
- /* @__PURE__ */ jsx(
4145
- Search,
4146
- {
4147
- size: 16,
4148
- style: {
4149
- position: "absolute",
4150
- top: "50%",
4151
- left: "28px",
4152
- transform: "translateY(-50%)",
4153
- color: theme.colors.textSecondary,
4154
- pointerEvents: "none"
4155
- }
4156
- }
4157
- ),
4158
- /* @__PURE__ */ jsx(
4159
- "input",
4160
- {
4161
- type: "text",
4162
- value: filter,
4163
- placeholder: "Filter starred repositories...",
4164
- onChange: (event) => setFilter(event.target.value),
4165
- style: {
4166
- width: "100%",
4167
- padding: "8px 12px 8px 36px",
4168
- borderRadius: "6px",
4169
- border: `1px solid ${theme.colors.border}`,
4170
- backgroundColor: theme.colors.background,
4171
- color: theme.colors.text,
4172
- fontSize: `${theme.fontSizes[1]}px`,
4173
- fontFamily: theme.fonts.body,
4174
- outline: "none",
4175
- boxSizing: "border-box"
4176
- }
4177
- }
4178
- )
4179
- ] }),
4180
4663
  error && repositories.length > 0 && /* @__PURE__ */ jsxs(
4181
4664
  "div",
4182
4665
  {
@@ -4218,7 +4701,10 @@ const GitHubStarredPanelContent = ({
4218
4701
  onClone: handleClone,
4219
4702
  onOpen: handleOpen,
4220
4703
  onSelect: handleSelect,
4221
- isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id
4704
+ isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id,
4705
+ onAddToCollection: currentWorkspace ? handleAddToCollection : void 0,
4706
+ isInCollection: collectionRepoSet.has(repo.full_name),
4707
+ collectionName
4222
4708
  },
4223
4709
  repo.id
4224
4710
  )),
@@ -4317,15 +4803,30 @@ const GitHubProjectsPanel = (props) => {
4317
4803
  const GitHubProjectsPanelContent = ({
4318
4804
  context,
4319
4805
  actions,
4320
- events
4806
+ events,
4807
+ defaultShowSearch = false
4321
4808
  }) => {
4322
- var _a, _b, _c, _d, _e, _f;
4809
+ var _a, _b, _c, _d, _e, _f, _g, _h;
4323
4810
  const { theme } = useTheme();
4324
4811
  const [filter, setFilter] = useState("");
4812
+ const [showSearch, setShowSearch] = useState(defaultShowSearch);
4325
4813
  const [collapsedSections, setCollapsedSections] = useState(/* @__PURE__ */ new Set());
4326
4814
  const [selectedRepo, setSelectedRepo] = useState(null);
4815
+ const handleToggleSearch = useCallback(() => {
4816
+ setShowSearch((prev) => {
4817
+ if (prev) {
4818
+ setFilter("");
4819
+ }
4820
+ return !prev;
4821
+ });
4822
+ }, []);
4823
+ const handleClearFilter = useCallback(() => {
4824
+ setFilter("");
4825
+ }, []);
4327
4826
  const projectsSlice = context.getSlice("githubProjects");
4328
4827
  const localReposSlice = context.getSlice("alexandriaRepositories");
4828
+ const workspaceSlice = context.getSlice("workspace");
4829
+ const workspaceReposSlice = context.getSlice("workspaceRepositories");
4329
4830
  const userRepositories = useMemo(
4330
4831
  () => {
4331
4832
  var _a2;
@@ -4357,6 +4858,18 @@ const GitHubProjectsPanelContent = ({
4357
4858
  },
4358
4859
  [(_f = localReposSlice == null ? void 0 : localReposSlice.data) == null ? void 0 : _f.repositories]
4359
4860
  );
4861
+ const currentWorkspace = (_g = workspaceSlice == null ? void 0 : workspaceSlice.data) == null ? void 0 : _g.workspace;
4862
+ const collectionName = currentWorkspace == null ? void 0 : currentWorkspace.name;
4863
+ const collectionRepos = useMemo(
4864
+ () => {
4865
+ var _a2;
4866
+ return ((_a2 = workspaceReposSlice == null ? void 0 : workspaceReposSlice.data) == null ? void 0 : _a2.repositories) || [];
4867
+ },
4868
+ [(_h = workspaceReposSlice == null ? void 0 : workspaceReposSlice.data) == null ? void 0 : _h.repositories]
4869
+ );
4870
+ const collectionRepoSet = useMemo(() => {
4871
+ return new Set(collectionRepos.map((r) => r.full_name));
4872
+ }, [collectionRepos]);
4360
4873
  const panelActions = actions;
4361
4874
  const localRepoMap = useMemo(() => {
4362
4875
  const map = /* @__PURE__ */ new Map();
@@ -4463,6 +4976,19 @@ const GitHubProjectsPanelContent = ({
4463
4976
  await panelActions.refreshProjects();
4464
4977
  }
4465
4978
  }, [panelActions]);
4979
+ const handleAddToCollection = useCallback(
4980
+ async (repo) => {
4981
+ if (panelActions.addToCollection) {
4982
+ await panelActions.addToCollection(repo);
4983
+ events.emit(
4984
+ createPanelEvent$1(`${PANEL_ID$8}:repository-added-to-collection`, {
4985
+ repository: repo
4986
+ })
4987
+ );
4988
+ }
4989
+ },
4990
+ [panelActions, events]
4991
+ );
4466
4992
  const toggleSection = useCallback((owner) => {
4467
4993
  setCollapsedSections((prev) => {
4468
4994
  const next = new Set(prev);
@@ -4741,68 +5267,167 @@ const GitHubProjectsPanelContent = ({
4741
5267
  "div",
4742
5268
  {
4743
5269
  style: {
5270
+ position: "relative",
4744
5271
  height: "40px",
4745
5272
  minHeight: "40px",
4746
5273
  padding: "0 16px",
4747
5274
  borderBottom: `1px solid ${theme.colors.border}`,
4748
5275
  display: "flex",
4749
5276
  alignItems: "center",
4750
- gap: "8px"
5277
+ boxSizing: "border-box"
4751
5278
  },
4752
5279
  children: [
4753
- /* @__PURE__ */ jsx(FolderGit2, { size: 18, color: theme.colors.primary }),
4754
- /* @__PURE__ */ jsx(
4755
- "span",
5280
+ /* @__PURE__ */ jsxs(
5281
+ "div",
4756
5282
  {
4757
5283
  style: {
4758
- fontSize: `${theme.fontSizes[2]}px`,
4759
- fontWeight: theme.fontWeights.medium,
4760
- color: theme.colors.text,
4761
- fontFamily: theme.fonts.body
5284
+ display: "flex",
5285
+ alignItems: "center",
5286
+ justifyContent: "space-between",
5287
+ width: "100%",
5288
+ visibility: showSearch ? "hidden" : "visible"
4762
5289
  },
4763
- children: "GitHub Projects"
5290
+ children: [
5291
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5292
+ /* @__PURE__ */ jsx(FolderGit2, { size: 18, color: theme.colors.primary }),
5293
+ /* @__PURE__ */ jsx(
5294
+ "span",
5295
+ {
5296
+ style: {
5297
+ fontSize: `${theme.fontSizes[2]}px`,
5298
+ fontWeight: theme.fontWeights.medium,
5299
+ color: theme.colors.text,
5300
+ fontFamily: theme.fonts.body
5301
+ },
5302
+ children: "GitHub Projects"
5303
+ }
5304
+ )
5305
+ ] }),
5306
+ /* @__PURE__ */ jsx(
5307
+ "button",
5308
+ {
5309
+ className: `header-button ${showSearch ? "active" : ""}`,
5310
+ onClick: handleToggleSearch,
5311
+ style: {
5312
+ background: showSearch ? theme.colors.backgroundSecondary : "none",
5313
+ border: `1px solid ${showSearch ? theme.colors.border : "transparent"}`,
5314
+ borderRadius: "4px",
5315
+ cursor: "pointer",
5316
+ padding: "4px",
5317
+ display: "flex",
5318
+ alignItems: "center",
5319
+ justifyContent: "center",
5320
+ color: showSearch ? theme.colors.primary : theme.colors.textSecondary,
5321
+ ["--theme-text"]: theme.colors.text
5322
+ },
5323
+ title: showSearch ? "Close search" : "Search repositories",
5324
+ children: /* @__PURE__ */ jsx(Search, { size: 16 })
5325
+ }
5326
+ )
5327
+ ]
5328
+ }
5329
+ ),
5330
+ showSearch && /* @__PURE__ */ jsxs(
5331
+ "div",
5332
+ {
5333
+ className: "search-overlay",
5334
+ style: {
5335
+ position: "absolute",
5336
+ top: 0,
5337
+ left: 0,
5338
+ right: 0,
5339
+ bottom: 0,
5340
+ display: "flex",
5341
+ alignItems: "center",
5342
+ padding: "0 16px",
5343
+ backgroundColor: theme.colors.backgroundSecondary,
5344
+ zIndex: 10
5345
+ },
5346
+ children: [
5347
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flex: 1, display: "flex", alignItems: "center" }, children: [
5348
+ /* @__PURE__ */ jsx(
5349
+ Search,
5350
+ {
5351
+ size: 16,
5352
+ color: theme.colors.textSecondary,
5353
+ style: {
5354
+ position: "absolute",
5355
+ left: "10px",
5356
+ pointerEvents: "none"
5357
+ }
5358
+ }
5359
+ ),
5360
+ /* @__PURE__ */ jsx(
5361
+ "input",
5362
+ {
5363
+ type: "text",
5364
+ className: "search-input",
5365
+ placeholder: "Filter repositories...",
5366
+ value: filter,
5367
+ onChange: (e) => setFilter(e.target.value),
5368
+ autoFocus: true,
5369
+ style: {
5370
+ width: "100%",
5371
+ padding: "6px 32px 6px 32px",
5372
+ fontSize: `${theme.fontSizes[1]}px`,
5373
+ color: theme.colors.text,
5374
+ backgroundColor: theme.colors.background,
5375
+ border: `1px solid ${theme.colors.border}`,
5376
+ borderRadius: "4px",
5377
+ outline: "none",
5378
+ fontFamily: theme.fonts.body,
5379
+ transition: "border-color 0.2s ease",
5380
+ ["--theme-primary"]: theme.colors.primary
5381
+ }
5382
+ }
5383
+ ),
5384
+ filter && /* @__PURE__ */ jsx(
5385
+ "button",
5386
+ {
5387
+ className: "clear-filter-button",
5388
+ onClick: handleClearFilter,
5389
+ style: {
5390
+ position: "absolute",
5391
+ right: "8px",
5392
+ background: "none",
5393
+ border: "none",
5394
+ cursor: "pointer",
5395
+ padding: "4px",
5396
+ display: "flex",
5397
+ alignItems: "center",
5398
+ justifyContent: "center",
5399
+ color: theme.colors.textSecondary,
5400
+ ["--theme-text"]: theme.colors.text
5401
+ },
5402
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
5403
+ }
5404
+ )
5405
+ ] }),
5406
+ /* @__PURE__ */ jsx(
5407
+ "button",
5408
+ {
5409
+ onClick: handleToggleSearch,
5410
+ style: {
5411
+ background: "none",
5412
+ border: "none",
5413
+ cursor: "pointer",
5414
+ padding: "4px",
5415
+ marginLeft: "8px",
5416
+ display: "flex",
5417
+ alignItems: "center",
5418
+ justifyContent: "center",
5419
+ color: theme.colors.textSecondary
5420
+ },
5421
+ title: "Close search",
5422
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
5423
+ }
5424
+ )
5425
+ ]
4764
5426
  }
4765
5427
  )
4766
5428
  ]
4767
5429
  }
4768
5430
  ),
4769
- /* @__PURE__ */ jsxs("div", { style: { position: "relative", padding: "8px 16px" }, children: [
4770
- /* @__PURE__ */ jsx(
4771
- Search,
4772
- {
4773
- size: 16,
4774
- style: {
4775
- position: "absolute",
4776
- top: "50%",
4777
- left: "28px",
4778
- transform: "translateY(-50%)",
4779
- color: theme.colors.textSecondary,
4780
- pointerEvents: "none"
4781
- }
4782
- }
4783
- ),
4784
- /* @__PURE__ */ jsx(
4785
- "input",
4786
- {
4787
- type: "text",
4788
- value: filter,
4789
- placeholder: "Filter repositories...",
4790
- onChange: (event) => setFilter(event.target.value),
4791
- style: {
4792
- width: "100%",
4793
- padding: "8px 12px 8px 36px",
4794
- borderRadius: "6px",
4795
- border: `1px solid ${theme.colors.border}`,
4796
- backgroundColor: theme.colors.background,
4797
- color: theme.colors.text,
4798
- fontSize: `${theme.fontSizes[1]}px`,
4799
- fontFamily: theme.fonts.body,
4800
- outline: "none",
4801
- boxSizing: "border-box"
4802
- }
4803
- }
4804
- )
4805
- ] }),
4806
5431
  error && hasData && /* @__PURE__ */ jsxs(
4807
5432
  "div",
4808
5433
  {
@@ -4852,7 +5477,10 @@ const GitHubProjectsPanelContent = ({
4852
5477
  onClone: handleClone,
4853
5478
  onOpen: handleOpen,
4854
5479
  onSelect: handleSelect,
4855
- isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id
5480
+ isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id,
5481
+ onAddToCollection: currentWorkspace ? handleAddToCollection : void 0,
5482
+ isInCollection: collectionRepoSet.has(repo.full_name),
5483
+ collectionName
4856
5484
  },
4857
5485
  repo.id
4858
5486
  )) })
@@ -4877,7 +5505,10 @@ const GitHubProjectsPanelContent = ({
4877
5505
  onClone: handleClone,
4878
5506
  onOpen: handleOpen,
4879
5507
  onSelect: handleSelect,
4880
- isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id
5508
+ isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id,
5509
+ onAddToCollection: currentWorkspace ? handleAddToCollection : void 0,
5510
+ isInCollection: collectionRepoSet.has(repo.full_name),
5511
+ collectionName
4881
5512
  },
4882
5513
  repo.id
4883
5514
  )) })