@phenx-inc/ctlsurf 0.12.0 → 0.13.1
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.
- package/out/headless/index.mjs +29 -19
- package/out/headless/index.mjs.map +2 -2
- package/out/main/index.js +35 -19
- package/out/renderer/assets/{cssMode-R8fTFLae.js → cssMode-KhYyY-BM.js} +3 -3
- package/out/renderer/assets/{freemarker2-CyjWzWoP.js → freemarker2-BFsSgcWk.js} +1 -1
- package/out/renderer/assets/{handlebars-CrhCGIRM.js → handlebars-Be6_aBsm.js} +1 -1
- package/out/renderer/assets/{html-Cc3dPNZr.js → html-G8mvsyfc.js} +1 -1
- package/out/renderer/assets/{htmlMode-BWtG6ywk.js → htmlMode-Cfd5VCjw.js} +3 -3
- package/out/renderer/assets/{index-BL9njXIL.css → index-Bi_MjBqs.css} +233 -8
- package/out/renderer/assets/{index-kkG56aKv.js → index-MqgBcJzy.js} +392 -120
- package/out/renderer/assets/{javascript-C8T_SdLC.js → javascript-XyDWi6dC.js} +2 -2
- package/out/renderer/assets/{jsonMode-D1zR4VVU.js → jsonMode-DZT5gBVW.js} +3 -3
- package/out/renderer/assets/{liquid-COSMe9Uf.js → liquid-BuajCNJ9.js} +1 -1
- package/out/renderer/assets/{lspLanguageFeatures-CXGfrtzl.js → lspLanguageFeatures-BYkg2Yc-.js} +1 -1
- package/out/renderer/assets/{mdx-RfS44T-L.js → mdx-D0Qx2GMS.js} +1 -1
- package/out/renderer/assets/{python-DFSWKHUu.js → python-ChncNy6S.js} +1 -1
- package/out/renderer/assets/{razor-DtH2_uvo.js → razor-C6MUtfaS.js} +1 -1
- package/out/renderer/assets/{tsMode-BYIQ-S9Z.js → tsMode-C2aMdzdU.js} +1 -1
- package/out/renderer/assets/{typescript-HhQUr1Rb.js → typescript-CB71AtAT.js} +1 -1
- package/out/renderer/assets/{xml-KuhgdKfD.js → xml-tHS1Ec9w.js} +1 -1
- package/out/renderer/assets/{yaml-W_kzCFH7.js → yaml-CZcp5ueF.js} +1 -1
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
- package/src/main/index.ts +13 -1
- package/src/main/orchestrator.ts +8 -1
- package/src/main/ticketStore.ts +26 -20
- package/src/renderer/App.tsx +19 -3
- package/src/renderer/components/CtlsurfPanel.tsx +169 -35
- package/src/renderer/components/SpeakControls.tsx +8 -2
- package/src/renderer/components/TerminalPanel.tsx +141 -44
- package/src/renderer/components/TicketPanel.tsx +126 -29
- package/src/renderer/styles.css +233 -8
package/out/main/index.js
CHANGED
|
@@ -11276,7 +11276,10 @@ function findPageByTitle(pages, title) {
|
|
|
11276
11276
|
}
|
|
11277
11277
|
class TicketStore {
|
|
11278
11278
|
api;
|
|
11279
|
-
|
|
11279
|
+
// Per-cwd cache of the resolved Tickets datastore: the block (the datastore
|
|
11280
|
+
// element) and the Agent Datastore page it lives on. Both ids are handed to
|
|
11281
|
+
// the coding agent so it can read/update tickets via the ctlsurf MCP tools.
|
|
11282
|
+
dsCache = /* @__PURE__ */ new Map();
|
|
11280
11283
|
constructor(api) {
|
|
11281
11284
|
this.api = api;
|
|
11282
11285
|
}
|
|
@@ -11285,11 +11288,11 @@ class TicketStore {
|
|
|
11285
11288
|
const title = input.title?.trim();
|
|
11286
11289
|
if (!title) return { ok: false, error: "Title is required" };
|
|
11287
11290
|
try {
|
|
11288
|
-
const
|
|
11289
|
-
if (!
|
|
11291
|
+
const ds = await this.ensureDatastore(cwd, true);
|
|
11292
|
+
if (!ds) {
|
|
11290
11293
|
return { ok: false, error: "No ctlsurf project found for this folder" };
|
|
11291
11294
|
}
|
|
11292
|
-
await this.api.addRow(blockId, {
|
|
11295
|
+
await this.api.addRow(ds.blockId, {
|
|
11293
11296
|
Title: title,
|
|
11294
11297
|
Description: input.description?.trim() || "",
|
|
11295
11298
|
Status: input.status || "Open",
|
|
@@ -11308,9 +11311,9 @@ class TicketStore {
|
|
|
11308
11311
|
const title = input.title?.trim();
|
|
11309
11312
|
if (!title) return { ok: false, error: "Title is required" };
|
|
11310
11313
|
try {
|
|
11311
|
-
const
|
|
11312
|
-
if (!
|
|
11313
|
-
await this.api.updateRow(blockId, rowId, {
|
|
11314
|
+
const ds = await this.ensureDatastore(cwd, false);
|
|
11315
|
+
if (!ds) return { ok: false, error: "No Tickets datastore for this project" };
|
|
11316
|
+
await this.api.updateRow(ds.blockId, rowId, {
|
|
11314
11317
|
Title: title,
|
|
11315
11318
|
Description: input.description?.trim() || "",
|
|
11316
11319
|
Status: input.status || "Open",
|
|
@@ -11327,9 +11330,9 @@ class TicketStore {
|
|
|
11327
11330
|
* datastore — an unconfigured project simply has no tickets yet. */
|
|
11328
11331
|
async listTickets(cwd) {
|
|
11329
11332
|
try {
|
|
11330
|
-
const
|
|
11331
|
-
if (!
|
|
11332
|
-
const res = await this.api.queryRows(blockId, { orderBy: "Created", order: "desc", limit: 200 });
|
|
11333
|
+
const ds = await this.ensureDatastore(cwd, false);
|
|
11334
|
+
if (!ds) return { ok: true, tickets: [] };
|
|
11335
|
+
const res = await this.api.queryRows(ds.blockId, { orderBy: "Created", order: "desc", limit: 200 });
|
|
11333
11336
|
const tickets = (res?.rows || []).map((r) => ({
|
|
11334
11337
|
id: r.id,
|
|
11335
11338
|
title: String(r.data?.Title ?? ""),
|
|
@@ -11338,14 +11341,14 @@ class TicketStore {
|
|
|
11338
11341
|
priority: String(r.data?.Priority ?? "Med"),
|
|
11339
11342
|
created: r.data?.Created ?? r.created_at ?? null
|
|
11340
11343
|
}));
|
|
11341
|
-
return { ok: true, tickets };
|
|
11344
|
+
return { ok: true, tickets, blockId: ds.blockId, pageId: ds.pageId };
|
|
11342
11345
|
} catch (err) {
|
|
11343
11346
|
log$1(`listTickets failed for ${cwd}: ${err?.message || err}`);
|
|
11344
11347
|
return { ok: false, tickets: [], error: err?.message || String(err) };
|
|
11345
11348
|
}
|
|
11346
11349
|
}
|
|
11347
11350
|
async ensureDatastore(cwd, create) {
|
|
11348
|
-
const cached = this.
|
|
11351
|
+
const cached = this.dsCache.get(cwd);
|
|
11349
11352
|
if (cached) return cached;
|
|
11350
11353
|
let folder = null;
|
|
11351
11354
|
try {
|
|
@@ -11357,11 +11360,13 @@ class TicketStore {
|
|
|
11357
11360
|
const folderDetail = await this.api.getFolder(folder.id);
|
|
11358
11361
|
const agentPage = findPageByTitle(folderDetail?.pages || [], AGENT_DATASTORE_PAGE_TITLE);
|
|
11359
11362
|
if (!agentPage?.id) return null;
|
|
11360
|
-
const
|
|
11363
|
+
const pageId = agentPage.id;
|
|
11364
|
+
const blockId = await this.findOrAdoptBlock(pageId);
|
|
11361
11365
|
if (blockId) {
|
|
11362
11366
|
await this.ensureColumns(blockId);
|
|
11363
|
-
|
|
11364
|
-
|
|
11367
|
+
const ds = { blockId, pageId };
|
|
11368
|
+
this.dsCache.set(cwd, ds);
|
|
11369
|
+
return ds;
|
|
11365
11370
|
}
|
|
11366
11371
|
if (!create) return null;
|
|
11367
11372
|
const columns = COLUMNS.map((c, i) => ({
|
|
@@ -11370,15 +11375,16 @@ class TicketStore {
|
|
|
11370
11375
|
type: c.type,
|
|
11371
11376
|
...c.options ? { options: c.options } : {}
|
|
11372
11377
|
}));
|
|
11373
|
-
const created = await this.api.createBlock(
|
|
11378
|
+
const created = await this.api.createBlock(pageId, {
|
|
11374
11379
|
type: "datastore",
|
|
11375
11380
|
title: DATASTORE_TITLE,
|
|
11376
11381
|
props: { columns, system_key: SYSTEM_KEY }
|
|
11377
11382
|
});
|
|
11378
11383
|
if (created?.id) {
|
|
11379
11384
|
log$1(`Created "${DATASTORE_TITLE}" datastore on Agent Datastore page for ${cwd}`);
|
|
11380
|
-
|
|
11381
|
-
|
|
11385
|
+
const ds = { blockId: created.id, pageId };
|
|
11386
|
+
this.dsCache.set(cwd, ds);
|
|
11387
|
+
return ds;
|
|
11382
11388
|
}
|
|
11383
11389
|
return null;
|
|
11384
11390
|
}
|
|
@@ -11924,12 +11930,16 @@ class Orchestrator {
|
|
|
11924
11930
|
}
|
|
11925
11931
|
}
|
|
11926
11932
|
setActiveTab(tabId) {
|
|
11933
|
+
const prevProjectPath = this.getActiveTabProjectPath();
|
|
11927
11934
|
this.activeTabId = tabId;
|
|
11928
11935
|
const tab = this.tabs.get(tabId);
|
|
11929
11936
|
if (tab) {
|
|
11930
11937
|
this.currentAgent = tab.agent;
|
|
11931
11938
|
this.currentCwd = tab.cwd;
|
|
11932
11939
|
}
|
|
11940
|
+
if (this.getActiveTabProjectPath() !== prevProjectPath) {
|
|
11941
|
+
this.events.onCwdChanged();
|
|
11942
|
+
}
|
|
11933
11943
|
}
|
|
11934
11944
|
getTabIds() {
|
|
11935
11945
|
return [...this.tabs.keys()];
|
|
@@ -12270,7 +12280,7 @@ const orchestrator = new Orchestrator(
|
|
|
12270
12280
|
},
|
|
12271
12281
|
onCwdChanged: () => {
|
|
12272
12282
|
mainWindow?.webContents.send("app:cwdChanged");
|
|
12273
|
-
updateProjectBadge(orchestrator.cwd);
|
|
12283
|
+
updateProjectBadge(orchestrator.getActiveTabProjectPath() || orchestrator.cwd);
|
|
12274
12284
|
}
|
|
12275
12285
|
}
|
|
12276
12286
|
);
|
|
@@ -12293,6 +12303,12 @@ function createWindow() {
|
|
|
12293
12303
|
mainWindow.webContents.session.setPermissionRequestHandler((_wc, _permission, callback) => {
|
|
12294
12304
|
callback(true);
|
|
12295
12305
|
});
|
|
12306
|
+
mainWindow.webContents.on("did-attach-webview", (_e, contents) => {
|
|
12307
|
+
contents.setWindowOpenHandler(({ url }) => {
|
|
12308
|
+
setImmediate(() => contents.loadURL(url));
|
|
12309
|
+
return { action: "deny" };
|
|
12310
|
+
});
|
|
12311
|
+
});
|
|
12296
12312
|
if (process.env.ELECTRON_RENDERER_URL) {
|
|
12297
12313
|
mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL);
|
|
12298
12314
|
} else {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { c as createWebWorker, l as languages } from "./index-
|
|
2
|
-
import { C as CompletionAdapter, H as HoverAdapter, D as DocumentHighlightAdapter, a as DefinitionAdapter, R as ReferenceAdapter, b as DocumentSymbolAdapter, c as RenameAdapter, d as DocumentColorAdapter, F as FoldingRangeAdapter, e as DiagnosticsAdapter, S as SelectionRangeAdapter, f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider } from "./lspLanguageFeatures-
|
|
3
|
-
import { h, i, j, t, k } from "./lspLanguageFeatures-
|
|
1
|
+
import { c as createWebWorker, l as languages } from "./index-MqgBcJzy.js";
|
|
2
|
+
import { C as CompletionAdapter, H as HoverAdapter, D as DocumentHighlightAdapter, a as DefinitionAdapter, R as ReferenceAdapter, b as DocumentSymbolAdapter, c as RenameAdapter, d as DocumentColorAdapter, F as FoldingRangeAdapter, e as DiagnosticsAdapter, S as SelectionRangeAdapter, f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider } from "./lspLanguageFeatures-BYkg2Yc-.js";
|
|
3
|
+
import { h, i, j, t, k } from "./lspLanguageFeatures-BYkg2Yc-.js";
|
|
4
4
|
const STOP_WHEN_IDLE_FOR = 2 * 60 * 1e3;
|
|
5
5
|
class WorkerManager {
|
|
6
6
|
constructor(defaults) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { c as createWebWorker, l as languages } from "./index-
|
|
2
|
-
import { H as HoverAdapter, D as DocumentHighlightAdapter, h as DocumentLinkAdapter, F as FoldingRangeAdapter, b as DocumentSymbolAdapter, S as SelectionRangeAdapter, c as RenameAdapter, f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider, C as CompletionAdapter } from "./lspLanguageFeatures-
|
|
3
|
-
import { a, e, d, R, i, j, t, k } from "./lspLanguageFeatures-
|
|
1
|
+
import { c as createWebWorker, l as languages } from "./index-MqgBcJzy.js";
|
|
2
|
+
import { H as HoverAdapter, D as DocumentHighlightAdapter, h as DocumentLinkAdapter, F as FoldingRangeAdapter, b as DocumentSymbolAdapter, S as SelectionRangeAdapter, c as RenameAdapter, f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider, C as CompletionAdapter } from "./lspLanguageFeatures-BYkg2Yc-.js";
|
|
3
|
+
import { a, e, d, R, i, j, t, k } from "./lspLanguageFeatures-BYkg2Yc-.js";
|
|
4
4
|
const STOP_WHEN_IDLE_FOR = 2 * 60 * 1e3;
|
|
5
5
|
class WorkerManager {
|
|
6
6
|
constructor(defaults) {
|
|
@@ -7486,6 +7486,17 @@ html, body, #root {
|
|
|
7486
7486
|
background: #1f2335;
|
|
7487
7487
|
}
|
|
7488
7488
|
|
|
7489
|
+
.titlebar-btn:disabled {
|
|
7490
|
+
opacity: 0.4;
|
|
7491
|
+
cursor: not-allowed;
|
|
7492
|
+
}
|
|
7493
|
+
|
|
7494
|
+
/* Keep the greyed-out look stable on hover for disabled buttons. */
|
|
7495
|
+
.titlebar-btn:disabled:hover {
|
|
7496
|
+
color: #565f89;
|
|
7497
|
+
border-color: #3b3d57;
|
|
7498
|
+
}
|
|
7499
|
+
|
|
7489
7500
|
.titlebar-separator {
|
|
7490
7501
|
width: 1px;
|
|
7491
7502
|
height: 16px;
|
|
@@ -7652,6 +7663,15 @@ html, body, #root {
|
|
|
7652
7663
|
}
|
|
7653
7664
|
|
|
7654
7665
|
/* Terminal container */
|
|
7666
|
+
.terminal-wrap {
|
|
7667
|
+
position: relative;
|
|
7668
|
+
flex: 1;
|
|
7669
|
+
min-width: 0;
|
|
7670
|
+
min-height: 0;
|
|
7671
|
+
width: 100%;
|
|
7672
|
+
height: 100%;
|
|
7673
|
+
}
|
|
7674
|
+
|
|
7655
7675
|
.terminal-container {
|
|
7656
7676
|
width: 100%;
|
|
7657
7677
|
height: 100%;
|
|
@@ -7663,6 +7683,34 @@ html, body, #root {
|
|
|
7663
7683
|
height: 100%;
|
|
7664
7684
|
}
|
|
7665
7685
|
|
|
7686
|
+
/* Floating "jump to latest" pill — shown only while scrolled up. */
|
|
7687
|
+
.term-jump-latest {
|
|
7688
|
+
position: absolute;
|
|
7689
|
+
bottom: 14px;
|
|
7690
|
+
right: 20px;
|
|
7691
|
+
z-index: 5;
|
|
7692
|
+
display: inline-flex;
|
|
7693
|
+
align-items: center;
|
|
7694
|
+
gap: 5px;
|
|
7695
|
+
padding: 5px 12px;
|
|
7696
|
+
border-radius: 14px;
|
|
7697
|
+
background: #2a2b3d;
|
|
7698
|
+
border: 1px solid #7aa2f7;
|
|
7699
|
+
color: #c0caf5;
|
|
7700
|
+
font-family: inherit;
|
|
7701
|
+
font-size: 11.5px;
|
|
7702
|
+
font-weight: 600;
|
|
7703
|
+
cursor: pointer;
|
|
7704
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
|
|
7705
|
+
transition: background 0.13s ease, transform 0.06s ease;
|
|
7706
|
+
}
|
|
7707
|
+
.term-jump-latest:hover {
|
|
7708
|
+
background: #343650;
|
|
7709
|
+
}
|
|
7710
|
+
.term-jump-latest:active {
|
|
7711
|
+
transform: translateY(1px);
|
|
7712
|
+
}
|
|
7713
|
+
|
|
7666
7714
|
.terminal-fullscreen {
|
|
7667
7715
|
width: 100%;
|
|
7668
7716
|
height: 100%;
|
|
@@ -7867,13 +7915,88 @@ html, body, #root {
|
|
|
7867
7915
|
width: 100%;
|
|
7868
7916
|
height: 100%;
|
|
7869
7917
|
overflow: hidden;
|
|
7918
|
+
display: flex;
|
|
7919
|
+
flex-direction: column;
|
|
7920
|
+
}
|
|
7921
|
+
|
|
7922
|
+
.ctlsurf-addressbar {
|
|
7923
|
+
flex: 0 0 auto;
|
|
7924
|
+
display: flex;
|
|
7925
|
+
align-items: center;
|
|
7926
|
+
gap: 4px;
|
|
7927
|
+
padding: 5px 6px;
|
|
7928
|
+
background: #1a1b26;
|
|
7929
|
+
border-bottom: 1px solid #2a2b3d;
|
|
7870
7930
|
}
|
|
7871
7931
|
|
|
7872
|
-
.ctlsurf-
|
|
7932
|
+
.ctlsurf-nav-btn {
|
|
7933
|
+
flex: 0 0 auto;
|
|
7934
|
+
width: 24px;
|
|
7935
|
+
height: 24px;
|
|
7936
|
+
display: flex;
|
|
7937
|
+
align-items: center;
|
|
7938
|
+
justify-content: center;
|
|
7939
|
+
padding: 0;
|
|
7940
|
+
background: transparent;
|
|
7941
|
+
border: none;
|
|
7942
|
+
border-radius: 4px;
|
|
7943
|
+
color: #a9b1d6;
|
|
7944
|
+
font-size: 16px;
|
|
7945
|
+
line-height: 1;
|
|
7946
|
+
cursor: pointer;
|
|
7947
|
+
}
|
|
7948
|
+
|
|
7949
|
+
.ctlsurf-nav-btn:hover:not(:disabled) {
|
|
7950
|
+
background: #2a2b3d;
|
|
7951
|
+
}
|
|
7952
|
+
|
|
7953
|
+
.ctlsurf-nav-btn:disabled {
|
|
7954
|
+
color: #565f89;
|
|
7955
|
+
opacity: 0.5;
|
|
7956
|
+
cursor: default;
|
|
7957
|
+
}
|
|
7958
|
+
|
|
7959
|
+
.ctlsurf-address-form {
|
|
7960
|
+
flex: 1 1 auto;
|
|
7961
|
+
display: flex;
|
|
7962
|
+
min-width: 0;
|
|
7963
|
+
}
|
|
7964
|
+
|
|
7965
|
+
.ctlsurf-address-input {
|
|
7966
|
+
width: 100%;
|
|
7967
|
+
height: 26px;
|
|
7968
|
+
padding: 0 11px;
|
|
7969
|
+
background: #16161e;
|
|
7970
|
+
border: 1px solid #2a2b3d;
|
|
7971
|
+
border-radius: 13px;
|
|
7972
|
+
color: #c0caf5;
|
|
7973
|
+
font-size: 12px;
|
|
7974
|
+
outline: none;
|
|
7975
|
+
}
|
|
7976
|
+
|
|
7977
|
+
.ctlsurf-address-input:focus {
|
|
7978
|
+
border-color: #7aa2f7;
|
|
7979
|
+
}
|
|
7980
|
+
|
|
7981
|
+
.ctlsurf-webview-host {
|
|
7982
|
+
flex: 1 1 auto;
|
|
7983
|
+
position: relative;
|
|
7984
|
+
min-height: 0;
|
|
7985
|
+
}
|
|
7986
|
+
|
|
7987
|
+
.ctlsurf-webview-host webview {
|
|
7873
7988
|
width: 100%;
|
|
7874
7989
|
height: 100%;
|
|
7875
7990
|
}
|
|
7876
7991
|
|
|
7992
|
+
.ctlsurf-webview-loading {
|
|
7993
|
+
width: 100%;
|
|
7994
|
+
height: 100%;
|
|
7995
|
+
display: flex;
|
|
7996
|
+
align-items: center;
|
|
7997
|
+
justify-content: center;
|
|
7998
|
+
}
|
|
7999
|
+
|
|
7877
8000
|
/* Status bar */
|
|
7878
8001
|
.statusbar {
|
|
7879
8002
|
height: 24px;
|
|
@@ -9098,6 +9221,32 @@ html, body, #root {
|
|
|
9098
9221
|
color: #7aa2f7;
|
|
9099
9222
|
font-weight: 600;
|
|
9100
9223
|
}
|
|
9224
|
+
/* "+ New" action in the header (replaces the old footer button). */
|
|
9225
|
+
.ticket-drawer-new {
|
|
9226
|
+
flex-shrink: 0;
|
|
9227
|
+
align-self: center;
|
|
9228
|
+
display: inline-flex;
|
|
9229
|
+
align-items: center;
|
|
9230
|
+
gap: 3px;
|
|
9231
|
+
padding: 5px 11px;
|
|
9232
|
+
border-radius: 7px;
|
|
9233
|
+
background: rgba(122, 162, 247, 0.14);
|
|
9234
|
+
border: 1px solid rgba(122, 162, 247, 0.3);
|
|
9235
|
+
color: #9db4f5;
|
|
9236
|
+
font-family: inherit;
|
|
9237
|
+
font-size: 12px;
|
|
9238
|
+
font-weight: 600;
|
|
9239
|
+
cursor: pointer;
|
|
9240
|
+
transition: background 0.13s ease, border-color 0.13s ease, color 0.13s ease, transform 0.06s ease;
|
|
9241
|
+
}
|
|
9242
|
+
.ticket-drawer-new:hover {
|
|
9243
|
+
background: rgba(122, 162, 247, 0.22);
|
|
9244
|
+
border-color: rgba(122, 162, 247, 0.5);
|
|
9245
|
+
color: #c0d0fb;
|
|
9246
|
+
}
|
|
9247
|
+
.ticket-drawer-new:active {
|
|
9248
|
+
transform: translateY(1px);
|
|
9249
|
+
}
|
|
9101
9250
|
.ticket-drawer-warn {
|
|
9102
9251
|
color: #e0af68;
|
|
9103
9252
|
}
|
|
@@ -9295,6 +9444,49 @@ html, body, #root {
|
|
|
9295
9444
|
text-align: center;
|
|
9296
9445
|
}
|
|
9297
9446
|
|
|
9447
|
+
/* ── collapsible "Done" section header ── */
|
|
9448
|
+
.ticket-done-toggle {
|
|
9449
|
+
display: flex;
|
|
9450
|
+
align-items: center;
|
|
9451
|
+
gap: 7px;
|
|
9452
|
+
width: 100%;
|
|
9453
|
+
margin-top: 3px;
|
|
9454
|
+
padding: 7px 4px;
|
|
9455
|
+
background: none;
|
|
9456
|
+
border: none;
|
|
9457
|
+
border-top: 1px solid #262a3f;
|
|
9458
|
+
color: #6b739b;
|
|
9459
|
+
font-family: inherit;
|
|
9460
|
+
font-size: 11.5px;
|
|
9461
|
+
font-weight: 600;
|
|
9462
|
+
letter-spacing: 0.03em;
|
|
9463
|
+
text-transform: uppercase;
|
|
9464
|
+
cursor: pointer;
|
|
9465
|
+
transition: color 0.13s ease;
|
|
9466
|
+
}
|
|
9467
|
+
.ticket-done-toggle:hover {
|
|
9468
|
+
color: #a9b1d6;
|
|
9469
|
+
}
|
|
9470
|
+
.ticket-done-caret {
|
|
9471
|
+
display: inline-block;
|
|
9472
|
+
font-size: 10px;
|
|
9473
|
+
transition: transform 0.13s ease;
|
|
9474
|
+
}
|
|
9475
|
+
.ticket-done-caret.open {
|
|
9476
|
+
transform: rotate(90deg);
|
|
9477
|
+
}
|
|
9478
|
+
.ticket-done-count {
|
|
9479
|
+
margin-left: auto;
|
|
9480
|
+
min-width: 18px;
|
|
9481
|
+
padding: 1px 6px;
|
|
9482
|
+
border-radius: 9px;
|
|
9483
|
+
background: #262a3f;
|
|
9484
|
+
color: #8088ac;
|
|
9485
|
+
font-size: 11px;
|
|
9486
|
+
font-weight: 600;
|
|
9487
|
+
text-align: center;
|
|
9488
|
+
}
|
|
9489
|
+
|
|
9298
9490
|
.ticket-empty {
|
|
9299
9491
|
display: flex;
|
|
9300
9492
|
flex-direction: column;
|
|
@@ -9321,24 +9513,57 @@ html, body, #root {
|
|
|
9321
9513
|
.ticket-card {
|
|
9322
9514
|
display: flex;
|
|
9323
9515
|
align-items: stretch;
|
|
9324
|
-
gap: 10px;
|
|
9325
9516
|
background: #15161f;
|
|
9326
9517
|
border: 1px solid #262a3f;
|
|
9327
9518
|
border-radius: 10px;
|
|
9328
|
-
padding: 10px 11px 10px 0;
|
|
9329
|
-
cursor: pointer;
|
|
9330
|
-
text-align: left;
|
|
9331
|
-
font-family: inherit;
|
|
9332
9519
|
overflow: hidden;
|
|
9333
|
-
transition: border-color 0.13s ease, background 0.13s ease
|
|
9520
|
+
transition: border-color 0.13s ease, background 0.13s ease;
|
|
9334
9521
|
}
|
|
9335
9522
|
.ticket-card:hover {
|
|
9336
9523
|
border-color: #3d425f;
|
|
9337
9524
|
background: #181a26;
|
|
9338
9525
|
}
|
|
9339
|
-
|
|
9526
|
+
/* Clickable body of the card — opens the editor. */
|
|
9527
|
+
.ticket-card-open {
|
|
9528
|
+
flex: 1;
|
|
9529
|
+
min-width: 0;
|
|
9530
|
+
display: flex;
|
|
9531
|
+
align-items: stretch;
|
|
9532
|
+
gap: 10px;
|
|
9533
|
+
padding: 10px 11px 10px 0;
|
|
9534
|
+
background: transparent;
|
|
9535
|
+
border: none;
|
|
9536
|
+
color: inherit;
|
|
9537
|
+
cursor: pointer;
|
|
9538
|
+
text-align: left;
|
|
9539
|
+
font-family: inherit;
|
|
9540
|
+
transition: transform 0.06s ease;
|
|
9541
|
+
}
|
|
9542
|
+
.ticket-card-open:active {
|
|
9340
9543
|
transform: scale(0.99);
|
|
9341
9544
|
}
|
|
9545
|
+
/* Trailing button that dispatches the ticket to the coding terminal. */
|
|
9546
|
+
.ticket-card-send {
|
|
9547
|
+
flex-shrink: 0;
|
|
9548
|
+
width: 36px;
|
|
9549
|
+
align-self: stretch;
|
|
9550
|
+
display: flex;
|
|
9551
|
+
align-items: center;
|
|
9552
|
+
justify-content: center;
|
|
9553
|
+
background: transparent;
|
|
9554
|
+
border: none;
|
|
9555
|
+
border-left: 1px solid #262a3f;
|
|
9556
|
+
color: #565f89;
|
|
9557
|
+
cursor: pointer;
|
|
9558
|
+
transition: background 0.13s ease, color 0.13s ease, transform 0.06s ease;
|
|
9559
|
+
}
|
|
9560
|
+
.ticket-card-send:hover {
|
|
9561
|
+
background: #1b2030;
|
|
9562
|
+
color: #7aa2f7;
|
|
9563
|
+
}
|
|
9564
|
+
.ticket-card-send:active {
|
|
9565
|
+
transform: scale(0.9);
|
|
9566
|
+
}
|
|
9342
9567
|
.ticket-card-bar {
|
|
9343
9568
|
width: 3px;
|
|
9344
9569
|
border-radius: 3px;
|