@industry-theme/alexandria-panels 0.1.22 → 0.1.23

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",
@@ -3811,12 +4155,26 @@ const GitHubStarredPanelContent = ({
3811
4155
  actions,
3812
4156
  events
3813
4157
  }) => {
3814
- var _a, _b, _c;
4158
+ var _a, _b, _c, _d, _e;
3815
4159
  const { theme } = useTheme();
3816
4160
  const [filter, setFilter] = useState("");
4161
+ const [showSearch, setShowSearch] = useState(false);
3817
4162
  const [selectedRepo, setSelectedRepo] = useState(null);
4163
+ const handleToggleSearch = useCallback(() => {
4164
+ setShowSearch((prev) => {
4165
+ if (prev) {
4166
+ setFilter("");
4167
+ }
4168
+ return !prev;
4169
+ });
4170
+ }, []);
4171
+ const handleClearFilter = useCallback(() => {
4172
+ setFilter("");
4173
+ }, []);
3818
4174
  const starredSlice = context.getSlice("githubStarred");
3819
4175
  const localReposSlice = context.getSlice("alexandriaRepositories");
4176
+ const workspaceSlice = context.getSlice("workspace");
4177
+ const workspaceReposSlice = context.getSlice("workspaceRepositories");
3820
4178
  const repositories = useMemo(
3821
4179
  () => {
3822
4180
  var _a2;
@@ -3833,6 +4191,18 @@ const GitHubStarredPanelContent = ({
3833
4191
  },
3834
4192
  [(_c = localReposSlice == null ? void 0 : localReposSlice.data) == null ? void 0 : _c.repositories]
3835
4193
  );
4194
+ const currentWorkspace = (_d = workspaceSlice == null ? void 0 : workspaceSlice.data) == null ? void 0 : _d.workspace;
4195
+ const collectionName = currentWorkspace == null ? void 0 : currentWorkspace.name;
4196
+ const collectionRepos = useMemo(
4197
+ () => {
4198
+ var _a2;
4199
+ return ((_a2 = workspaceReposSlice == null ? void 0 : workspaceReposSlice.data) == null ? void 0 : _a2.repositories) || [];
4200
+ },
4201
+ [(_e = workspaceReposSlice == null ? void 0 : workspaceReposSlice.data) == null ? void 0 : _e.repositories]
4202
+ );
4203
+ const collectionRepoSet = useMemo(() => {
4204
+ return new Set(collectionRepos.map((r) => r.full_name));
4205
+ }, [collectionRepos]);
3836
4206
  const panelActions = actions;
3837
4207
  const localRepoMap = useMemo(() => {
3838
4208
  const map = /* @__PURE__ */ new Map();
@@ -3918,6 +4288,19 @@ const GitHubStarredPanelContent = ({
3918
4288
  await panelActions.refreshStarred();
3919
4289
  }
3920
4290
  }, [panelActions]);
4291
+ const handleAddToCollection = useCallback(
4292
+ async (repo) => {
4293
+ if (panelActions.addToCollection) {
4294
+ await panelActions.addToCollection(repo);
4295
+ events.emit(
4296
+ createPanelEvent$2(`${PANEL_ID$9}:repository-added-to-collection`, {
4297
+ repository: repo
4298
+ })
4299
+ );
4300
+ }
4301
+ },
4302
+ [panelActions, events]
4303
+ );
3921
4304
  useEffect(() => {
3922
4305
  const unsubscribers = [
3923
4306
  events.on(`${PANEL_ID$9}:filter`, (event) => {
@@ -4102,81 +4485,180 @@ const GitHubStarredPanelContent = ({
4102
4485
  "div",
4103
4486
  {
4104
4487
  style: {
4488
+ position: "relative",
4105
4489
  height: "40px",
4106
4490
  minHeight: "40px",
4107
4491
  padding: "0 16px",
4108
4492
  borderBottom: `1px solid ${theme.colors.border}`,
4109
4493
  display: "flex",
4110
4494
  alignItems: "center",
4111
- gap: "8px"
4495
+ boxSizing: "border-box"
4112
4496
  },
4113
4497
  children: [
4114
- /* @__PURE__ */ jsx(Star, { size: 18, style: { color: "#f59e0b" } }),
4115
- /* @__PURE__ */ jsx(
4116
- "span",
4498
+ /* @__PURE__ */ jsxs(
4499
+ "div",
4117
4500
  {
4118
4501
  style: {
4119
- fontSize: `${theme.fontSizes[2]}px`,
4120
- fontWeight: theme.fontWeights.medium,
4121
- color: theme.colors.text,
4122
- fontFamily: theme.fonts.body
4502
+ display: "flex",
4503
+ alignItems: "center",
4504
+ justifyContent: "space-between",
4505
+ width: "100%",
4506
+ visibility: showSearch ? "hidden" : "visible"
4123
4507
  },
4124
- children: "Starred"
4508
+ children: [
4509
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
4510
+ /* @__PURE__ */ jsx(Star, { size: 18, style: { color: "#f59e0b" } }),
4511
+ /* @__PURE__ */ jsx(
4512
+ "span",
4513
+ {
4514
+ style: {
4515
+ fontSize: `${theme.fontSizes[2]}px`,
4516
+ fontWeight: theme.fontWeights.medium,
4517
+ color: theme.colors.text,
4518
+ fontFamily: theme.fonts.body
4519
+ },
4520
+ children: "Starred"
4521
+ }
4522
+ ),
4523
+ repositories.length > 0 && /* @__PURE__ */ jsx(
4524
+ "span",
4525
+ {
4526
+ style: {
4527
+ fontSize: `${theme.fontSizes[1]}px`,
4528
+ color: theme.colors.textSecondary,
4529
+ padding: "2px 8px",
4530
+ borderRadius: "12px",
4531
+ backgroundColor: theme.colors.background
4532
+ },
4533
+ children: repositories.length
4534
+ }
4535
+ )
4536
+ ] }),
4537
+ /* @__PURE__ */ jsx(
4538
+ "button",
4539
+ {
4540
+ className: `header-button ${showSearch ? "active" : ""}`,
4541
+ onClick: handleToggleSearch,
4542
+ style: {
4543
+ background: showSearch ? theme.colors.backgroundSecondary : "none",
4544
+ border: `1px solid ${showSearch ? theme.colors.border : "transparent"}`,
4545
+ borderRadius: "4px",
4546
+ cursor: "pointer",
4547
+ padding: "4px",
4548
+ display: "flex",
4549
+ alignItems: "center",
4550
+ justifyContent: "center",
4551
+ color: showSearch ? theme.colors.primary : theme.colors.textSecondary,
4552
+ ["--theme-text"]: theme.colors.text
4553
+ },
4554
+ title: showSearch ? "Close search" : "Search repositories",
4555
+ children: /* @__PURE__ */ jsx(Search, { size: 16 })
4556
+ }
4557
+ )
4558
+ ]
4125
4559
  }
4126
4560
  ),
4127
- repositories.length > 0 && /* @__PURE__ */ jsx(
4128
- "span",
4561
+ showSearch && /* @__PURE__ */ jsxs(
4562
+ "div",
4129
4563
  {
4564
+ className: "search-overlay",
4130
4565
  style: {
4131
- fontSize: `${theme.fontSizes[1]}px`,
4132
- color: theme.colors.textSecondary,
4133
- padding: "2px 8px",
4134
- borderRadius: "12px",
4135
- backgroundColor: theme.colors.background
4566
+ position: "absolute",
4567
+ top: 0,
4568
+ left: 0,
4569
+ right: 0,
4570
+ bottom: 0,
4571
+ display: "flex",
4572
+ alignItems: "center",
4573
+ padding: "0 16px",
4574
+ backgroundColor: theme.colors.backgroundSecondary,
4575
+ zIndex: 10
4136
4576
  },
4137
- children: repositories.length
4577
+ children: [
4578
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flex: 1, display: "flex", alignItems: "center" }, children: [
4579
+ /* @__PURE__ */ jsx(
4580
+ Search,
4581
+ {
4582
+ size: 16,
4583
+ color: theme.colors.textSecondary,
4584
+ style: {
4585
+ position: "absolute",
4586
+ left: "10px",
4587
+ pointerEvents: "none"
4588
+ }
4589
+ }
4590
+ ),
4591
+ /* @__PURE__ */ jsx(
4592
+ "input",
4593
+ {
4594
+ type: "text",
4595
+ className: "search-input",
4596
+ placeholder: "Filter starred repositories...",
4597
+ value: filter,
4598
+ onChange: (e) => setFilter(e.target.value),
4599
+ autoFocus: true,
4600
+ style: {
4601
+ width: "100%",
4602
+ padding: "6px 32px 6px 32px",
4603
+ fontSize: `${theme.fontSizes[1]}px`,
4604
+ color: theme.colors.text,
4605
+ backgroundColor: theme.colors.background,
4606
+ border: `1px solid ${theme.colors.border}`,
4607
+ borderRadius: "4px",
4608
+ outline: "none",
4609
+ fontFamily: theme.fonts.body,
4610
+ transition: "border-color 0.2s ease",
4611
+ ["--theme-primary"]: theme.colors.primary
4612
+ }
4613
+ }
4614
+ ),
4615
+ filter && /* @__PURE__ */ jsx(
4616
+ "button",
4617
+ {
4618
+ className: "clear-filter-button",
4619
+ onClick: handleClearFilter,
4620
+ style: {
4621
+ position: "absolute",
4622
+ right: "8px",
4623
+ background: "none",
4624
+ border: "none",
4625
+ cursor: "pointer",
4626
+ padding: "4px",
4627
+ display: "flex",
4628
+ alignItems: "center",
4629
+ justifyContent: "center",
4630
+ color: theme.colors.textSecondary,
4631
+ ["--theme-text"]: theme.colors.text
4632
+ },
4633
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
4634
+ }
4635
+ )
4636
+ ] }),
4637
+ /* @__PURE__ */ jsx(
4638
+ "button",
4639
+ {
4640
+ onClick: handleToggleSearch,
4641
+ style: {
4642
+ background: "none",
4643
+ border: "none",
4644
+ cursor: "pointer",
4645
+ padding: "4px",
4646
+ marginLeft: "8px",
4647
+ display: "flex",
4648
+ alignItems: "center",
4649
+ justifyContent: "center",
4650
+ color: theme.colors.textSecondary
4651
+ },
4652
+ title: "Close search",
4653
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
4654
+ }
4655
+ )
4656
+ ]
4138
4657
  }
4139
4658
  )
4140
4659
  ]
4141
4660
  }
4142
4661
  ),
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
4662
  error && repositories.length > 0 && /* @__PURE__ */ jsxs(
4181
4663
  "div",
4182
4664
  {
@@ -4218,7 +4700,10 @@ const GitHubStarredPanelContent = ({
4218
4700
  onClone: handleClone,
4219
4701
  onOpen: handleOpen,
4220
4702
  onSelect: handleSelect,
4221
- isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id
4703
+ isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id,
4704
+ onAddToCollection: currentWorkspace ? handleAddToCollection : void 0,
4705
+ isInCollection: collectionRepoSet.has(repo.full_name),
4706
+ collectionName
4222
4707
  },
4223
4708
  repo.id
4224
4709
  )),
@@ -4319,13 +4804,27 @@ const GitHubProjectsPanelContent = ({
4319
4804
  actions,
4320
4805
  events
4321
4806
  }) => {
4322
- var _a, _b, _c, _d, _e, _f;
4807
+ var _a, _b, _c, _d, _e, _f, _g, _h;
4323
4808
  const { theme } = useTheme();
4324
4809
  const [filter, setFilter] = useState("");
4810
+ const [showSearch, setShowSearch] = useState(false);
4325
4811
  const [collapsedSections, setCollapsedSections] = useState(/* @__PURE__ */ new Set());
4326
4812
  const [selectedRepo, setSelectedRepo] = useState(null);
4813
+ const handleToggleSearch = useCallback(() => {
4814
+ setShowSearch((prev) => {
4815
+ if (prev) {
4816
+ setFilter("");
4817
+ }
4818
+ return !prev;
4819
+ });
4820
+ }, []);
4821
+ const handleClearFilter = useCallback(() => {
4822
+ setFilter("");
4823
+ }, []);
4327
4824
  const projectsSlice = context.getSlice("githubProjects");
4328
4825
  const localReposSlice = context.getSlice("alexandriaRepositories");
4826
+ const workspaceSlice = context.getSlice("workspace");
4827
+ const workspaceReposSlice = context.getSlice("workspaceRepositories");
4329
4828
  const userRepositories = useMemo(
4330
4829
  () => {
4331
4830
  var _a2;
@@ -4357,6 +4856,18 @@ const GitHubProjectsPanelContent = ({
4357
4856
  },
4358
4857
  [(_f = localReposSlice == null ? void 0 : localReposSlice.data) == null ? void 0 : _f.repositories]
4359
4858
  );
4859
+ const currentWorkspace = (_g = workspaceSlice == null ? void 0 : workspaceSlice.data) == null ? void 0 : _g.workspace;
4860
+ const collectionName = currentWorkspace == null ? void 0 : currentWorkspace.name;
4861
+ const collectionRepos = useMemo(
4862
+ () => {
4863
+ var _a2;
4864
+ return ((_a2 = workspaceReposSlice == null ? void 0 : workspaceReposSlice.data) == null ? void 0 : _a2.repositories) || [];
4865
+ },
4866
+ [(_h = workspaceReposSlice == null ? void 0 : workspaceReposSlice.data) == null ? void 0 : _h.repositories]
4867
+ );
4868
+ const collectionRepoSet = useMemo(() => {
4869
+ return new Set(collectionRepos.map((r) => r.full_name));
4870
+ }, [collectionRepos]);
4360
4871
  const panelActions = actions;
4361
4872
  const localRepoMap = useMemo(() => {
4362
4873
  const map = /* @__PURE__ */ new Map();
@@ -4463,6 +4974,19 @@ const GitHubProjectsPanelContent = ({
4463
4974
  await panelActions.refreshProjects();
4464
4975
  }
4465
4976
  }, [panelActions]);
4977
+ const handleAddToCollection = useCallback(
4978
+ async (repo) => {
4979
+ if (panelActions.addToCollection) {
4980
+ await panelActions.addToCollection(repo);
4981
+ events.emit(
4982
+ createPanelEvent$1(`${PANEL_ID$8}:repository-added-to-collection`, {
4983
+ repository: repo
4984
+ })
4985
+ );
4986
+ }
4987
+ },
4988
+ [panelActions, events]
4989
+ );
4466
4990
  const toggleSection = useCallback((owner) => {
4467
4991
  setCollapsedSections((prev) => {
4468
4992
  const next = new Set(prev);
@@ -4741,68 +5265,167 @@ const GitHubProjectsPanelContent = ({
4741
5265
  "div",
4742
5266
  {
4743
5267
  style: {
5268
+ position: "relative",
4744
5269
  height: "40px",
4745
5270
  minHeight: "40px",
4746
5271
  padding: "0 16px",
4747
5272
  borderBottom: `1px solid ${theme.colors.border}`,
4748
5273
  display: "flex",
4749
5274
  alignItems: "center",
4750
- gap: "8px"
5275
+ boxSizing: "border-box"
4751
5276
  },
4752
5277
  children: [
4753
- /* @__PURE__ */ jsx(FolderGit2, { size: 18, color: theme.colors.primary }),
4754
- /* @__PURE__ */ jsx(
4755
- "span",
5278
+ /* @__PURE__ */ jsxs(
5279
+ "div",
4756
5280
  {
4757
5281
  style: {
4758
- fontSize: `${theme.fontSizes[2]}px`,
4759
- fontWeight: theme.fontWeights.medium,
4760
- color: theme.colors.text,
4761
- fontFamily: theme.fonts.body
5282
+ display: "flex",
5283
+ alignItems: "center",
5284
+ justifyContent: "space-between",
5285
+ width: "100%",
5286
+ visibility: showSearch ? "hidden" : "visible"
5287
+ },
5288
+ children: [
5289
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5290
+ /* @__PURE__ */ jsx(FolderGit2, { size: 18, color: theme.colors.primary }),
5291
+ /* @__PURE__ */ jsx(
5292
+ "span",
5293
+ {
5294
+ style: {
5295
+ fontSize: `${theme.fontSizes[2]}px`,
5296
+ fontWeight: theme.fontWeights.medium,
5297
+ color: theme.colors.text,
5298
+ fontFamily: theme.fonts.body
5299
+ },
5300
+ children: "GitHub Projects"
5301
+ }
5302
+ )
5303
+ ] }),
5304
+ /* @__PURE__ */ jsx(
5305
+ "button",
5306
+ {
5307
+ className: `header-button ${showSearch ? "active" : ""}`,
5308
+ onClick: handleToggleSearch,
5309
+ style: {
5310
+ background: showSearch ? theme.colors.backgroundSecondary : "none",
5311
+ border: `1px solid ${showSearch ? theme.colors.border : "transparent"}`,
5312
+ borderRadius: "4px",
5313
+ cursor: "pointer",
5314
+ padding: "4px",
5315
+ display: "flex",
5316
+ alignItems: "center",
5317
+ justifyContent: "center",
5318
+ color: showSearch ? theme.colors.primary : theme.colors.textSecondary,
5319
+ ["--theme-text"]: theme.colors.text
5320
+ },
5321
+ title: showSearch ? "Close search" : "Search repositories",
5322
+ children: /* @__PURE__ */ jsx(Search, { size: 16 })
5323
+ }
5324
+ )
5325
+ ]
5326
+ }
5327
+ ),
5328
+ showSearch && /* @__PURE__ */ jsxs(
5329
+ "div",
5330
+ {
5331
+ className: "search-overlay",
5332
+ style: {
5333
+ position: "absolute",
5334
+ top: 0,
5335
+ left: 0,
5336
+ right: 0,
5337
+ bottom: 0,
5338
+ display: "flex",
5339
+ alignItems: "center",
5340
+ padding: "0 16px",
5341
+ backgroundColor: theme.colors.backgroundSecondary,
5342
+ zIndex: 10
4762
5343
  },
4763
- children: "GitHub Projects"
5344
+ children: [
5345
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flex: 1, display: "flex", alignItems: "center" }, children: [
5346
+ /* @__PURE__ */ jsx(
5347
+ Search,
5348
+ {
5349
+ size: 16,
5350
+ color: theme.colors.textSecondary,
5351
+ style: {
5352
+ position: "absolute",
5353
+ left: "10px",
5354
+ pointerEvents: "none"
5355
+ }
5356
+ }
5357
+ ),
5358
+ /* @__PURE__ */ jsx(
5359
+ "input",
5360
+ {
5361
+ type: "text",
5362
+ className: "search-input",
5363
+ placeholder: "Filter repositories...",
5364
+ value: filter,
5365
+ onChange: (e) => setFilter(e.target.value),
5366
+ autoFocus: true,
5367
+ style: {
5368
+ width: "100%",
5369
+ padding: "6px 32px 6px 32px",
5370
+ fontSize: `${theme.fontSizes[1]}px`,
5371
+ color: theme.colors.text,
5372
+ backgroundColor: theme.colors.background,
5373
+ border: `1px solid ${theme.colors.border}`,
5374
+ borderRadius: "4px",
5375
+ outline: "none",
5376
+ fontFamily: theme.fonts.body,
5377
+ transition: "border-color 0.2s ease",
5378
+ ["--theme-primary"]: theme.colors.primary
5379
+ }
5380
+ }
5381
+ ),
5382
+ filter && /* @__PURE__ */ jsx(
5383
+ "button",
5384
+ {
5385
+ className: "clear-filter-button",
5386
+ onClick: handleClearFilter,
5387
+ style: {
5388
+ position: "absolute",
5389
+ right: "8px",
5390
+ background: "none",
5391
+ border: "none",
5392
+ cursor: "pointer",
5393
+ padding: "4px",
5394
+ display: "flex",
5395
+ alignItems: "center",
5396
+ justifyContent: "center",
5397
+ color: theme.colors.textSecondary,
5398
+ ["--theme-text"]: theme.colors.text
5399
+ },
5400
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
5401
+ }
5402
+ )
5403
+ ] }),
5404
+ /* @__PURE__ */ jsx(
5405
+ "button",
5406
+ {
5407
+ onClick: handleToggleSearch,
5408
+ style: {
5409
+ background: "none",
5410
+ border: "none",
5411
+ cursor: "pointer",
5412
+ padding: "4px",
5413
+ marginLeft: "8px",
5414
+ display: "flex",
5415
+ alignItems: "center",
5416
+ justifyContent: "center",
5417
+ color: theme.colors.textSecondary
5418
+ },
5419
+ title: "Close search",
5420
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
5421
+ }
5422
+ )
5423
+ ]
4764
5424
  }
4765
5425
  )
4766
5426
  ]
4767
5427
  }
4768
5428
  ),
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
5429
  error && hasData && /* @__PURE__ */ jsxs(
4807
5430
  "div",
4808
5431
  {
@@ -4852,7 +5475,10 @@ const GitHubProjectsPanelContent = ({
4852
5475
  onClone: handleClone,
4853
5476
  onOpen: handleOpen,
4854
5477
  onSelect: handleSelect,
4855
- isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id
5478
+ isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id,
5479
+ onAddToCollection: currentWorkspace ? handleAddToCollection : void 0,
5480
+ isInCollection: collectionRepoSet.has(repo.full_name),
5481
+ collectionName
4856
5482
  },
4857
5483
  repo.id
4858
5484
  )) })
@@ -4877,7 +5503,10 @@ const GitHubProjectsPanelContent = ({
4877
5503
  onClone: handleClone,
4878
5504
  onOpen: handleOpen,
4879
5505
  onSelect: handleSelect,
4880
- isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id
5506
+ isSelected: (selectedRepo == null ? void 0 : selectedRepo.id) === repo.id,
5507
+ onAddToCollection: currentWorkspace ? handleAddToCollection : void 0,
5508
+ isInCollection: collectionRepoSet.has(repo.full_name),
5509
+ collectionName
4881
5510
  },
4882
5511
  repo.id
4883
5512
  )) })