clay-server 2.15.2 → 2.16.0-beta.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/lib/daemon.js +9 -0
- package/lib/project.js +156 -15
- package/lib/public/app.js +381 -83
- package/lib/public/css/command-palette.css +43 -3
- package/lib/public/css/filebrowser.css +28 -3
- package/lib/public/css/home-hub.css +77 -0
- package/lib/public/css/icon-strip.css +15 -1
- package/lib/public/css/input.css +1 -1
- package/lib/public/css/mates.css +207 -3
- package/lib/public/css/messages.css +44 -2
- package/lib/public/css/mobile-nav.css +412 -7
- package/lib/public/css/rewind.css +13 -0
- package/lib/public/css/server-settings.css +21 -5
- package/lib/public/css/session-search.css +1 -1
- package/lib/public/css/sidebar.css +20 -2
- package/lib/public/css/title-bar.css +1 -23
- package/lib/public/index.html +57 -6
- package/lib/public/modules/longpress.js +74 -0
- package/lib/public/modules/mate-knowledge.js +30 -0
- package/lib/public/modules/mate-sidebar.js +14 -9
- package/lib/public/modules/notifications.js +10 -0
- package/lib/public/modules/project-settings.js +14 -0
- package/lib/public/modules/server-settings.js +17 -0
- package/lib/public/modules/sidebar.js +681 -31
- package/lib/public/modules/stt.js +5 -1
- package/lib/public/modules/terminal.js +28 -1
- package/lib/public/modules/tools.js +5 -1
- package/lib/sdk-bridge.js +7 -6
- package/lib/server.js +53 -3
- package/package.json +1 -1
|
@@ -3,10 +3,12 @@ import { iconHtml, refreshIcons } from './icons.js';
|
|
|
3
3
|
import { openProjectSettings } from './project-settings.js';
|
|
4
4
|
import { triggerShare } from './qrcode.js';
|
|
5
5
|
import { parseEmojis } from './markdown.js';
|
|
6
|
+
import { getCurrentTheme } from './theme.js';
|
|
6
7
|
import { showMateProfilePopover } from './profile.js';
|
|
7
8
|
import { closeArchive } from './sticky-notes.js';
|
|
8
9
|
import { closeScheduler } from './scheduler.js';
|
|
9
10
|
import { openSearch as openSessionSearch } from './session-search.js';
|
|
11
|
+
import { openCommandPalette } from './command-palette.js';
|
|
10
12
|
|
|
11
13
|
var ctx;
|
|
12
14
|
|
|
@@ -20,6 +22,7 @@ var expandedLoopGroups = new Set();
|
|
|
20
22
|
// --- Cached project data for mobile sheet ---
|
|
21
23
|
var cachedProjectList = [];
|
|
22
24
|
var cachedCurrentSlug = null;
|
|
25
|
+
var mobileChatSheetOpen = false; // track if chat sheet is showing
|
|
23
26
|
|
|
24
27
|
function dismissOverlayPanels() {
|
|
25
28
|
closeArchive();
|
|
@@ -483,6 +486,9 @@ function renderSessionItem(s) {
|
|
|
483
486
|
export function renderSessionList(sessions) {
|
|
484
487
|
if (sessions) cachedSessions = sessions;
|
|
485
488
|
|
|
489
|
+
// If mobile chat sheet is open, refresh its session list
|
|
490
|
+
refreshMobileChatSheet();
|
|
491
|
+
|
|
486
492
|
ctx.sessionListEl.innerHTML = "";
|
|
487
493
|
|
|
488
494
|
// Partition: loop sessions vs normal sessions
|
|
@@ -644,9 +650,15 @@ export function closeSidebar() {
|
|
|
644
650
|
ctx.sidebarOverlay.classList.remove("visible");
|
|
645
651
|
}
|
|
646
652
|
|
|
647
|
-
// --- Mobile sheet (fullscreen overlay for Projects / Sessions) ---
|
|
653
|
+
// --- Mobile sheet (fullscreen overlay for Projects / Sessions / Mate Profile) ---
|
|
654
|
+
|
|
655
|
+
var mobileSheetMateData = null;
|
|
656
|
+
|
|
657
|
+
export function setMobileSheetMateData(data) {
|
|
658
|
+
mobileSheetMateData = data;
|
|
659
|
+
}
|
|
648
660
|
|
|
649
|
-
function openMobileSheet(type) {
|
|
661
|
+
export function openMobileSheet(type) {
|
|
650
662
|
var sheet = document.getElementById("mobile-sheet");
|
|
651
663
|
if (!sheet) return;
|
|
652
664
|
|
|
@@ -660,15 +672,21 @@ function openMobileSheet(type) {
|
|
|
660
672
|
var prevPanel = document.getElementById("sidebar-panel-files");
|
|
661
673
|
if (prevFileTree && prevPanel) prevPanel.appendChild(prevFileTree);
|
|
662
674
|
}
|
|
675
|
+
// Return knowledge files to mate sidebar before clearing
|
|
676
|
+
if (sheet.classList.contains("sheet-knowledge")) {
|
|
677
|
+
var prevKnowledge = document.getElementById("mate-knowledge-files");
|
|
678
|
+
var prevKnowledgePanel = document.getElementById("mate-sidebar-knowledge");
|
|
679
|
+
if (prevKnowledge && prevKnowledgePanel) prevKnowledgePanel.appendChild(prevKnowledge);
|
|
680
|
+
}
|
|
663
681
|
|
|
664
682
|
listEl.innerHTML = "";
|
|
665
|
-
sheet.classList.remove("sheet-files");
|
|
683
|
+
sheet.classList.remove("sheet-files", "sheet-knowledge");
|
|
666
684
|
|
|
667
685
|
if (type === "projects") {
|
|
668
686
|
titleEl.textContent = "Projects";
|
|
669
687
|
renderSheetProjects(listEl);
|
|
670
688
|
} else if (type === "sessions") {
|
|
671
|
-
titleEl.textContent = "
|
|
689
|
+
titleEl.textContent = "Chat";
|
|
672
690
|
renderSheetSessions(listEl);
|
|
673
691
|
} else if (type === "files") {
|
|
674
692
|
titleEl.textContent = "Files";
|
|
@@ -679,6 +697,28 @@ function openMobileSheet(type) {
|
|
|
679
697
|
fileTree.classList.remove("hidden");
|
|
680
698
|
}
|
|
681
699
|
if (ctx.onFilesTabOpen) ctx.onFilesTabOpen();
|
|
700
|
+
} else if (type === "mate-knowledge") {
|
|
701
|
+
titleEl.textContent = "Knowledge";
|
|
702
|
+
sheet.classList.add("sheet-knowledge");
|
|
703
|
+
var knowledgeFiles = document.getElementById("mate-knowledge-files");
|
|
704
|
+
if (knowledgeFiles) {
|
|
705
|
+
listEl.appendChild(knowledgeFiles);
|
|
706
|
+
knowledgeFiles.classList.remove("hidden");
|
|
707
|
+
}
|
|
708
|
+
// Request knowledge list if not loaded
|
|
709
|
+
if (ctx.requestKnowledgeList) ctx.requestKnowledgeList();
|
|
710
|
+
} else if (type === "mate-profile") {
|
|
711
|
+
titleEl.textContent = "";
|
|
712
|
+
renderSheetMateProfile(listEl);
|
|
713
|
+
} else if (type === "search") {
|
|
714
|
+
titleEl.textContent = "Search";
|
|
715
|
+
renderSheetSearch(listEl);
|
|
716
|
+
} else if (type === "tools") {
|
|
717
|
+
titleEl.textContent = "Tools";
|
|
718
|
+
renderSheetTools(listEl);
|
|
719
|
+
} else if (type === "settings") {
|
|
720
|
+
titleEl.textContent = "Settings";
|
|
721
|
+
renderSheetSettings(listEl);
|
|
682
722
|
}
|
|
683
723
|
|
|
684
724
|
sheet.classList.remove("hidden", "closing");
|
|
@@ -689,6 +729,8 @@ function closeMobileSheet() {
|
|
|
689
729
|
var sheet = document.getElementById("mobile-sheet");
|
|
690
730
|
if (!sheet || sheet.classList.contains("hidden")) return;
|
|
691
731
|
|
|
732
|
+
mobileChatSheetOpen = false;
|
|
733
|
+
|
|
692
734
|
// Return file tree to sidebar if it was moved
|
|
693
735
|
if (sheet.classList.contains("sheet-files")) {
|
|
694
736
|
var fileTree = document.getElementById("file-tree");
|
|
@@ -697,6 +739,14 @@ function closeMobileSheet() {
|
|
|
697
739
|
sidebarFilesPanel.appendChild(fileTree);
|
|
698
740
|
}
|
|
699
741
|
}
|
|
742
|
+
// Return knowledge files to mate sidebar if moved
|
|
743
|
+
if (sheet.classList.contains("sheet-knowledge")) {
|
|
744
|
+
var knowledgeFiles = document.getElementById("mate-knowledge-files");
|
|
745
|
+
var knowledgePanel = document.getElementById("mate-sidebar-knowledge");
|
|
746
|
+
if (knowledgeFiles && knowledgePanel) {
|
|
747
|
+
knowledgePanel.appendChild(knowledgeFiles);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
700
750
|
|
|
701
751
|
sheet.classList.add("closing");
|
|
702
752
|
setTimeout(function () {
|
|
@@ -713,7 +763,12 @@ function renderSheetProjects(listEl) {
|
|
|
713
763
|
|
|
714
764
|
var abbrev = document.createElement("span");
|
|
715
765
|
abbrev.className = "mobile-project-abbrev";
|
|
716
|
-
|
|
766
|
+
if (p.icon) {
|
|
767
|
+
abbrev.textContent = p.icon;
|
|
768
|
+
parseEmojis(abbrev);
|
|
769
|
+
} else {
|
|
770
|
+
abbrev.textContent = getProjectAbbrev(p.name);
|
|
771
|
+
}
|
|
717
772
|
el.appendChild(abbrev);
|
|
718
773
|
|
|
719
774
|
var name = document.createElement("span");
|
|
@@ -745,7 +800,208 @@ function renderSheetProjects(listEl) {
|
|
|
745
800
|
}
|
|
746
801
|
|
|
747
802
|
function renderSheetSessions(listEl) {
|
|
748
|
-
//
|
|
803
|
+
// --- Context filter bar (horizontal scroll) ---
|
|
804
|
+
var filterBar = document.createElement("div");
|
|
805
|
+
filterBar.className = "mobile-chat-filter-bar";
|
|
806
|
+
|
|
807
|
+
// Current project chip (always first, pre-selected)
|
|
808
|
+
var currentProject = null;
|
|
809
|
+
for (var pi = 0; pi < cachedProjectList.length; pi++) {
|
|
810
|
+
if (cachedProjectList[pi].slug === cachedCurrentSlug) {
|
|
811
|
+
currentProject = cachedProjectList[pi];
|
|
812
|
+
break;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// Build chips: projects first, then mates
|
|
817
|
+
var chips = [];
|
|
818
|
+
|
|
819
|
+
for (var ci = 0; ci < cachedProjectList.length; ci++) {
|
|
820
|
+
(function (p) {
|
|
821
|
+
var chip = document.createElement("button");
|
|
822
|
+
chip.className = "mobile-chat-chip";
|
|
823
|
+
if (p.slug === cachedCurrentSlug) chip.classList.add("active");
|
|
824
|
+
chip.dataset.type = "project";
|
|
825
|
+
chip.dataset.slug = p.slug;
|
|
826
|
+
|
|
827
|
+
var abbrev = document.createElement("span");
|
|
828
|
+
abbrev.className = "mobile-chat-chip-icon";
|
|
829
|
+
if (p.icon) {
|
|
830
|
+
abbrev.textContent = p.icon;
|
|
831
|
+
parseEmojis(abbrev);
|
|
832
|
+
} else {
|
|
833
|
+
abbrev.textContent = getProjectAbbrev(p.name);
|
|
834
|
+
}
|
|
835
|
+
chip.appendChild(abbrev);
|
|
836
|
+
|
|
837
|
+
var label = document.createElement("span");
|
|
838
|
+
label.textContent = p.name;
|
|
839
|
+
chip.appendChild(label);
|
|
840
|
+
|
|
841
|
+
// Processing dot: same class as icon strip
|
|
842
|
+
var statusDot = document.createElement("span");
|
|
843
|
+
statusDot.className = "icon-strip-status";
|
|
844
|
+
if (p.isProcessing) statusDot.classList.add("processing");
|
|
845
|
+
chip.appendChild(statusDot);
|
|
846
|
+
|
|
847
|
+
if (p.unread > 0 && p.slug !== cachedCurrentSlug) {
|
|
848
|
+
var badge = document.createElement("span");
|
|
849
|
+
badge.className = "mobile-chat-chip-badge";
|
|
850
|
+
badge.textContent = p.unread > 99 ? "99+" : String(p.unread);
|
|
851
|
+
chip.appendChild(badge);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
chips.push(chip);
|
|
855
|
+
})(cachedProjectList[ci]);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
for (var mi = 0; mi < cachedMates.length; mi++) {
|
|
859
|
+
(function (mate) {
|
|
860
|
+
var mp = mate.profile || {};
|
|
861
|
+
var chip = document.createElement("button");
|
|
862
|
+
chip.className = "mobile-chat-chip";
|
|
863
|
+
chip.dataset.type = "mate";
|
|
864
|
+
chip.dataset.mateId = mate.id;
|
|
865
|
+
|
|
866
|
+
var avatarEl = document.createElement("img");
|
|
867
|
+
avatarEl.className = "mobile-chat-chip-avatar";
|
|
868
|
+
avatarEl.src = "https://api.dicebear.com/9.x/" + (mp.avatarStyle || "bottts") + "/svg?seed=" + encodeURIComponent(mp.avatarSeed || mate.id) + "&size=20";
|
|
869
|
+
avatarEl.alt = mp.displayName || mate.name || "";
|
|
870
|
+
chip.appendChild(avatarEl);
|
|
871
|
+
|
|
872
|
+
var label = document.createElement("span");
|
|
873
|
+
label.textContent = mp.displayName || mate.name || "Mate";
|
|
874
|
+
chip.appendChild(label);
|
|
875
|
+
|
|
876
|
+
// Processing dot: same class as icon strip, same data source
|
|
877
|
+
var mateSlug = "mate-" + mate.id;
|
|
878
|
+
var mateProj = null;
|
|
879
|
+
var allProjects = (ctx && ctx.projectList) || [];
|
|
880
|
+
for (var pi = 0; pi < allProjects.length; pi++) {
|
|
881
|
+
if (allProjects[pi].slug === mateSlug) { mateProj = allProjects[pi]; break; }
|
|
882
|
+
}
|
|
883
|
+
var statusDot = document.createElement("span");
|
|
884
|
+
statusDot.className = "icon-strip-status";
|
|
885
|
+
if (mateProj && mateProj.isProcessing) statusDot.classList.add("processing");
|
|
886
|
+
chip.appendChild(statusDot);
|
|
887
|
+
|
|
888
|
+
var unreadCount = cachedDmUnread[mate.id] || 0;
|
|
889
|
+
if (unreadCount > 0) {
|
|
890
|
+
var badge = document.createElement("span");
|
|
891
|
+
badge.className = "mobile-chat-chip-badge";
|
|
892
|
+
badge.textContent = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
893
|
+
chip.appendChild(badge);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
chips.push(chip);
|
|
897
|
+
})(cachedMates[mi]);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
for (var i = 0; i < chips.length; i++) {
|
|
901
|
+
filterBar.appendChild(chips[i]);
|
|
902
|
+
}
|
|
903
|
+
listEl.appendChild(filterBar);
|
|
904
|
+
|
|
905
|
+
// --- Session list container ---
|
|
906
|
+
var sessionListEl = document.createElement("div");
|
|
907
|
+
sessionListEl.className = "mobile-chat-session-list";
|
|
908
|
+
listEl.appendChild(sessionListEl);
|
|
909
|
+
|
|
910
|
+
// --- Render sessions for a context ---
|
|
911
|
+
function renderSessionsForContext(type, slug, mateId) {
|
|
912
|
+
sessionListEl.innerHTML = "";
|
|
913
|
+
|
|
914
|
+
if (type === "project") {
|
|
915
|
+
renderMobileSessionsInto(sessionListEl);
|
|
916
|
+
} else if (type === "mate") {
|
|
917
|
+
// Mate DM: just open the DM
|
|
918
|
+
if (ctx.openDm) ctx.openDm(mateId);
|
|
919
|
+
closeMobileSheet();
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
refreshIcons();
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// --- Chip click handlers ---
|
|
927
|
+
for (var j = 0; j < chips.length; j++) {
|
|
928
|
+
(function (chip) {
|
|
929
|
+
chip.addEventListener("click", function () {
|
|
930
|
+
// Deactivate all chips
|
|
931
|
+
for (var k = 0; k < chips.length; k++) {
|
|
932
|
+
chips[k].classList.remove("active");
|
|
933
|
+
}
|
|
934
|
+
chip.classList.add("active");
|
|
935
|
+
|
|
936
|
+
var type = chip.dataset.type;
|
|
937
|
+
if (type === "project") {
|
|
938
|
+
var slug = chip.dataset.slug;
|
|
939
|
+
if (slug !== cachedCurrentSlug) {
|
|
940
|
+
// Switch project, show loading, keep sheet open
|
|
941
|
+
sessionListEl.innerHTML = "";
|
|
942
|
+
var loading = document.createElement("div");
|
|
943
|
+
loading.className = "mobile-chat-context-note";
|
|
944
|
+
loading.textContent = "Loading sessions...";
|
|
945
|
+
sessionListEl.appendChild(loading);
|
|
946
|
+
if (ctx.switchProject) ctx.switchProject(slug);
|
|
947
|
+
// renderSessionList will be called by WS, which calls refreshMobileChatSheet
|
|
948
|
+
} else {
|
|
949
|
+
renderSessionsForContext("project", slug, null);
|
|
950
|
+
}
|
|
951
|
+
} else if (type === "mate") {
|
|
952
|
+
renderSessionsForContext("mate", null, chip.dataset.mateId);
|
|
953
|
+
}
|
|
954
|
+
});
|
|
955
|
+
})(chips[j]);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// Track that chat sheet is open
|
|
959
|
+
mobileChatSheetOpen = true;
|
|
960
|
+
|
|
961
|
+
// --- Initial render: current project sessions ---
|
|
962
|
+
renderSessionsForContext("project", cachedCurrentSlug, null);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// Helper: create a mobile session item element
|
|
966
|
+
function createMobileSessionItem(s) {
|
|
967
|
+
var el = document.createElement("button");
|
|
968
|
+
el.className = "mobile-session-item" + (s.active ? " active" : "");
|
|
969
|
+
|
|
970
|
+
// Processing dot (left side, before title)
|
|
971
|
+
if (s.isProcessing) {
|
|
972
|
+
var dot = document.createElement("span");
|
|
973
|
+
dot.className = "mobile-session-processing";
|
|
974
|
+
el.appendChild(dot);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
var titleSpan = document.createElement("span");
|
|
978
|
+
titleSpan.className = "mobile-session-title";
|
|
979
|
+
titleSpan.textContent = s.title || "New Session";
|
|
980
|
+
el.appendChild(titleSpan);
|
|
981
|
+
|
|
982
|
+
// Unread badge (right side)
|
|
983
|
+
if (s.unread > 0 && !s.active) {
|
|
984
|
+
var badge = document.createElement("span");
|
|
985
|
+
badge.className = "mobile-session-unread";
|
|
986
|
+
badge.textContent = s.unread > 99 ? "99+" : String(s.unread);
|
|
987
|
+
el.appendChild(badge);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
(function (id) {
|
|
991
|
+
el.addEventListener("click", function () {
|
|
992
|
+
if (ctx.ws && ctx.connected) {
|
|
993
|
+
ctx.ws.send(JSON.stringify({ type: "switch_session", id: id }));
|
|
994
|
+
}
|
|
995
|
+
dismissOverlayPanels();
|
|
996
|
+
closeMobileSheet();
|
|
997
|
+
});
|
|
998
|
+
})(s.id);
|
|
999
|
+
|
|
1000
|
+
return el;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// Helper: render sorted sessions into a container with date groups
|
|
1004
|
+
function renderMobileSessionsInto(container) {
|
|
749
1005
|
var newBtn = document.createElement("button");
|
|
750
1006
|
newBtn.className = "mobile-session-new";
|
|
751
1007
|
newBtn.innerHTML = '<i data-lucide="plus" style="width:16px;height:16px"></i> New session';
|
|
@@ -755,30 +1011,186 @@ function renderSheetSessions(listEl) {
|
|
|
755
1011
|
}
|
|
756
1012
|
closeMobileSheet();
|
|
757
1013
|
});
|
|
758
|
-
|
|
1014
|
+
container.appendChild(newBtn);
|
|
759
1015
|
|
|
760
1016
|
var sorted = cachedSessions.slice().sort(function (a, b) {
|
|
761
1017
|
return (b.lastActivity || 0) - (a.lastActivity || 0);
|
|
762
1018
|
});
|
|
763
1019
|
|
|
764
1020
|
var currentGroup = "";
|
|
765
|
-
for (var
|
|
766
|
-
var s = sorted[
|
|
1021
|
+
for (var si = 0; si < sorted.length; si++) {
|
|
1022
|
+
var s = sorted[si];
|
|
767
1023
|
var group = getDateGroup(s.lastActivity || 0);
|
|
768
1024
|
if (group !== currentGroup) {
|
|
769
1025
|
currentGroup = group;
|
|
770
1026
|
var header = document.createElement("div");
|
|
771
1027
|
header.className = "mobile-sheet-group";
|
|
772
1028
|
header.textContent = group;
|
|
773
|
-
|
|
1029
|
+
container.appendChild(header);
|
|
1030
|
+
}
|
|
1031
|
+
container.appendChild(createMobileSessionItem(s));
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// Refresh mobile chat sheet when session data updates (called from renderSessionList)
|
|
1036
|
+
function refreshMobileChatSheet() {
|
|
1037
|
+
if (!mobileChatSheetOpen) return;
|
|
1038
|
+
var sheet = document.getElementById("mobile-sheet");
|
|
1039
|
+
if (!sheet || sheet.classList.contains("hidden")) {
|
|
1040
|
+
mobileChatSheetOpen = false;
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
var sessionListEl = sheet.querySelector(".mobile-chat-session-list");
|
|
1044
|
+
if (!sessionListEl) return;
|
|
1045
|
+
|
|
1046
|
+
// Update chips: active state and processing dots
|
|
1047
|
+
var chips = sheet.querySelectorAll(".mobile-chat-chip");
|
|
1048
|
+
for (var i = 0; i < chips.length; i++) {
|
|
1049
|
+
var chip = chips[i];
|
|
1050
|
+
chip.classList.remove("active");
|
|
1051
|
+
|
|
1052
|
+
// Update active state
|
|
1053
|
+
if (chip.dataset.type === "project" && chip.dataset.slug === cachedCurrentSlug) {
|
|
1054
|
+
chip.classList.add("active");
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// Update processing dot: same class as icon strip
|
|
1058
|
+
var statusDot = chip.querySelector(".icon-strip-status");
|
|
1059
|
+
if (statusDot) {
|
|
1060
|
+
var isProcessing = false;
|
|
1061
|
+
var allProjects = (ctx && ctx.projectList) || [];
|
|
1062
|
+
var lookupSlug = chip.dataset.type === "mate" ? ("mate-" + chip.dataset.mateId) : chip.dataset.slug;
|
|
1063
|
+
for (var pi = 0; pi < allProjects.length; pi++) {
|
|
1064
|
+
if (allProjects[pi].slug === lookupSlug && allProjects[pi].isProcessing) {
|
|
1065
|
+
isProcessing = true;
|
|
1066
|
+
break;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
statusDot.classList.toggle("processing", isProcessing);
|
|
774
1070
|
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
// Re-render sessions for current project
|
|
1074
|
+
sessionListEl.innerHTML = "";
|
|
1075
|
+
renderMobileSessionsInto(sessionListEl);
|
|
1076
|
+
|
|
1077
|
+
refreshIcons();
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function renderSheetMateProfile(listEl) {
|
|
1081
|
+
if (!mobileSheetMateData) return;
|
|
1082
|
+
var data = mobileSheetMateData;
|
|
1083
|
+
|
|
1084
|
+
// Profile header
|
|
1085
|
+
var header = document.createElement("div");
|
|
1086
|
+
header.className = "mate-profile-header";
|
|
1087
|
+
|
|
1088
|
+
var avatar = document.createElement("img");
|
|
1089
|
+
avatar.className = "mate-profile-avatar";
|
|
1090
|
+
avatar.src = data.avatarUrl || "";
|
|
1091
|
+
avatar.alt = data.displayName || "";
|
|
1092
|
+
header.appendChild(avatar);
|
|
1093
|
+
|
|
1094
|
+
var info = document.createElement("div");
|
|
1095
|
+
info.className = "mate-profile-info";
|
|
1096
|
+
var nameEl = document.createElement("div");
|
|
1097
|
+
nameEl.className = "mate-profile-name";
|
|
1098
|
+
nameEl.textContent = data.displayName || "";
|
|
1099
|
+
info.appendChild(nameEl);
|
|
1100
|
+
if (data.description) {
|
|
1101
|
+
var descEl = document.createElement("div");
|
|
1102
|
+
descEl.className = "mate-profile-desc";
|
|
1103
|
+
descEl.textContent = data.description;
|
|
1104
|
+
info.appendChild(descEl);
|
|
1105
|
+
}
|
|
1106
|
+
header.appendChild(info);
|
|
1107
|
+
listEl.appendChild(header);
|
|
1108
|
+
|
|
1109
|
+
// Action buttons
|
|
1110
|
+
var actions = [
|
|
1111
|
+
{ icon: "book-open", label: "Knowledge", btnId: "mate-knowledge-btn", countId: "mate-knowledge-count" },
|
|
1112
|
+
{ icon: "sticky-note", label: "Sticky Notes", btnId: "sticky-notes-toggle-btn", countId: "sticky-notes-sidebar-count" },
|
|
1113
|
+
{ icon: "puzzle", label: "Skills", btnId: "mate-skills-btn" },
|
|
1114
|
+
{ icon: "calendar", label: "Scheduled Tasks", btnId: "mate-scheduler-btn" }
|
|
1115
|
+
];
|
|
1116
|
+
|
|
1117
|
+
for (var i = 0; i < actions.length; i++) {
|
|
1118
|
+
(function (action) {
|
|
1119
|
+
var btn = document.createElement("button");
|
|
1120
|
+
btn.className = "mate-profile-action";
|
|
1121
|
+
var countHtml = "";
|
|
1122
|
+
if (action.countId) {
|
|
1123
|
+
var countEl = document.getElementById(action.countId);
|
|
1124
|
+
if (countEl && !countEl.classList.contains("hidden") && countEl.textContent) {
|
|
1125
|
+
countHtml = '<span class="mate-profile-action-count">' + escapeHtml(countEl.textContent) + '</span>';
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
btn.innerHTML = '<i data-lucide="' + action.icon + '"></i><span>' + action.label + '</span>' + countHtml;
|
|
1129
|
+
btn.addEventListener("click", function () {
|
|
1130
|
+
closeMobileSheet();
|
|
1131
|
+
var targetBtn = document.getElementById(action.btnId);
|
|
1132
|
+
if (targetBtn) {
|
|
1133
|
+
setTimeout(function () { targetBtn.click(); }, 250);
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
listEl.appendChild(btn);
|
|
1137
|
+
})(actions[i]);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
function renderSheetSearch(listEl) {
|
|
1142
|
+
// Search input at top
|
|
1143
|
+
var wrap = document.createElement("div");
|
|
1144
|
+
wrap.className = "mobile-search-input-wrap";
|
|
1145
|
+
var input = document.createElement("input");
|
|
1146
|
+
input.className = "mobile-search-input";
|
|
1147
|
+
input.type = "text";
|
|
1148
|
+
input.placeholder = "Search sessions, messages...";
|
|
1149
|
+
input.autocomplete = "off";
|
|
1150
|
+
input.spellcheck = false;
|
|
1151
|
+
wrap.appendChild(input);
|
|
1152
|
+
listEl.appendChild(wrap);
|
|
1153
|
+
|
|
1154
|
+
// Results container
|
|
1155
|
+
var resultsEl = document.createElement("div");
|
|
1156
|
+
resultsEl.style.padding = "0 8px";
|
|
1157
|
+
listEl.appendChild(resultsEl);
|
|
1158
|
+
|
|
1159
|
+
// Auto-focus
|
|
1160
|
+
setTimeout(function () { input.focus(); }, 300);
|
|
1161
|
+
|
|
1162
|
+
// Show all sessions initially
|
|
1163
|
+
renderSearchResults(resultsEl, "");
|
|
1164
|
+
|
|
1165
|
+
input.addEventListener("input", function () {
|
|
1166
|
+
var q = input.value.trim().toLowerCase();
|
|
1167
|
+
renderSearchResults(resultsEl, q);
|
|
1168
|
+
});
|
|
1169
|
+
input.addEventListener("keydown", function (e) { e.stopPropagation(); });
|
|
1170
|
+
input.addEventListener("keyup", function (e) { e.stopPropagation(); });
|
|
1171
|
+
input.addEventListener("keypress", function (e) { e.stopPropagation(); });
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
function renderSearchResults(container, query) {
|
|
1175
|
+
container.innerHTML = "";
|
|
1176
|
+
var sorted = cachedSessions.slice().sort(function (a, b) {
|
|
1177
|
+
return (b.lastActivity || 0) - (a.lastActivity || 0);
|
|
1178
|
+
});
|
|
1179
|
+
|
|
1180
|
+
var found = 0;
|
|
1181
|
+
for (var i = 0; i < sorted.length; i++) {
|
|
1182
|
+
var s = sorted[i];
|
|
1183
|
+
var title = s.title || "New Session";
|
|
1184
|
+
if (query && title.toLowerCase().indexOf(query) === -1) continue;
|
|
1185
|
+
found++;
|
|
775
1186
|
|
|
776
1187
|
var el = document.createElement("button");
|
|
777
|
-
el.className = "mobile-session-item"
|
|
1188
|
+
el.className = "mobile-session-item";
|
|
1189
|
+
if (s.active) el.classList.add("active");
|
|
778
1190
|
|
|
779
1191
|
var titleSpan = document.createElement("span");
|
|
780
1192
|
titleSpan.className = "mobile-session-title";
|
|
781
|
-
titleSpan.textContent =
|
|
1193
|
+
titleSpan.textContent = title;
|
|
782
1194
|
el.appendChild(titleSpan);
|
|
783
1195
|
|
|
784
1196
|
if (s.isProcessing) {
|
|
@@ -797,10 +1209,128 @@ function renderSheetSessions(listEl) {
|
|
|
797
1209
|
});
|
|
798
1210
|
})(s.id);
|
|
799
1211
|
|
|
800
|
-
|
|
1212
|
+
container.appendChild(el);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
if (found === 0 && query) {
|
|
1216
|
+
var empty = document.createElement("div");
|
|
1217
|
+
empty.className = "mobile-alert-empty";
|
|
1218
|
+
empty.textContent = 'No results for "' + query + '"';
|
|
1219
|
+
container.appendChild(empty);
|
|
801
1220
|
}
|
|
802
1221
|
}
|
|
803
1222
|
|
|
1223
|
+
function renderSheetTools(listEl) {
|
|
1224
|
+
var isMateDm = document.body.classList.contains("mate-dm-active");
|
|
1225
|
+
|
|
1226
|
+
var items = isMateDm ? [
|
|
1227
|
+
{ icon: "book-open", label: "Knowledge", action: "mate-knowledge" },
|
|
1228
|
+
{ icon: "calendar-clock", label: "Scheduled Tasks", action: "mate-scheduler" }
|
|
1229
|
+
] : [
|
|
1230
|
+
{ icon: "folder-tree", label: "Files", action: "files" },
|
|
1231
|
+
{ icon: "square-terminal", label: "Terminal", action: "terminal" },
|
|
1232
|
+
{ icon: "calendar-clock", label: "Scheduled Tasks", action: "scheduler" }
|
|
1233
|
+
];
|
|
1234
|
+
|
|
1235
|
+
for (var i = 0; i < items.length; i++) {
|
|
1236
|
+
(function (item) {
|
|
1237
|
+
var btn = document.createElement("button");
|
|
1238
|
+
btn.className = "mobile-more-item";
|
|
1239
|
+
btn.innerHTML = '<i data-lucide="' + item.icon + '"></i><span class="mobile-more-item-label">' + item.label + '</span>';
|
|
1240
|
+
btn.addEventListener("click", function () {
|
|
1241
|
+
closeMobileSheet();
|
|
1242
|
+
var targetId = null;
|
|
1243
|
+
if (item.action === "files") {
|
|
1244
|
+
setTimeout(function () { openMobileSheet("files"); }, 250);
|
|
1245
|
+
} else if (item.action === "terminal") {
|
|
1246
|
+
if (ctx.openTerminal) ctx.openTerminal();
|
|
1247
|
+
} else if (item.action === "scheduler") {
|
|
1248
|
+
targetId = "scheduler-btn";
|
|
1249
|
+
} else if (item.action === "mate-knowledge") {
|
|
1250
|
+
setTimeout(function () { openMobileSheet("mate-knowledge"); }, 250);
|
|
1251
|
+
return;
|
|
1252
|
+
} else if (item.action === "mate-sticky") {
|
|
1253
|
+
targetId = "sticky-notes-toggle-btn";
|
|
1254
|
+
} else if (item.action === "mate-skills") {
|
|
1255
|
+
targetId = "mate-skills-btn";
|
|
1256
|
+
} else if (item.action === "mate-scheduler") {
|
|
1257
|
+
targetId = "mate-scheduler-btn";
|
|
1258
|
+
}
|
|
1259
|
+
if (targetId) {
|
|
1260
|
+
var targetBtn = document.getElementById(targetId);
|
|
1261
|
+
if (targetBtn) setTimeout(function () { targetBtn.click(); }, 250);
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1264
|
+
listEl.appendChild(btn);
|
|
1265
|
+
})(items[i]);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
function renderSheetSettings(listEl) {
|
|
1270
|
+
var items = [
|
|
1271
|
+
{ icon: "folder-cog", label: "Project Settings", action: "project-settings" },
|
|
1272
|
+
{ icon: "settings", label: "Server Settings", action: "server-settings" }
|
|
1273
|
+
];
|
|
1274
|
+
|
|
1275
|
+
for (var i = 0; i < items.length; i++) {
|
|
1276
|
+
(function (item) {
|
|
1277
|
+
var btn = document.createElement("button");
|
|
1278
|
+
btn.className = "mobile-more-item";
|
|
1279
|
+
btn.innerHTML = '<i data-lucide="' + item.icon + '"></i><span class="mobile-more-item-label">' + item.label + '</span>';
|
|
1280
|
+
btn.addEventListener("click", function () {
|
|
1281
|
+
closeMobileSheet();
|
|
1282
|
+
if (item.action === "project-settings") {
|
|
1283
|
+
setTimeout(function () {
|
|
1284
|
+
// Find current project data
|
|
1285
|
+
var proj = null;
|
|
1286
|
+
for (var pi = 0; pi < cachedAllProjects.length; pi++) {
|
|
1287
|
+
if (cachedAllProjects[pi].slug === cachedCurrentSlug) {
|
|
1288
|
+
proj = cachedAllProjects[pi];
|
|
1289
|
+
break;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
// For mate projects, use mate display name instead of slug
|
|
1293
|
+
if (proj && proj.isMate && cachedMates.length > 0) {
|
|
1294
|
+
var mateId = cachedCurrentSlug.replace("mate-", "");
|
|
1295
|
+
for (var mi = 0; mi < cachedMates.length; mi++) {
|
|
1296
|
+
var mp = cachedMates[mi].profile || {};
|
|
1297
|
+
if (cachedMates[mi].id === mateId) {
|
|
1298
|
+
proj = Object.assign({}, proj, { name: mp.displayName || cachedMates[mi].name || proj.name });
|
|
1299
|
+
break;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
openProjectSettings(cachedCurrentSlug, proj);
|
|
1304
|
+
}, 250);
|
|
1305
|
+
} else if (item.action === "server-settings") {
|
|
1306
|
+
var settingsBtn = document.getElementById("server-settings-btn");
|
|
1307
|
+
if (settingsBtn) setTimeout(function () { settingsBtn.click(); }, 250);
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
listEl.appendChild(btn);
|
|
1311
|
+
})(items[i]);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// Dark/Light switch button
|
|
1315
|
+
var isDark = getCurrentTheme().variant === "dark";
|
|
1316
|
+
var themeBtn = document.createElement("button");
|
|
1317
|
+
themeBtn.className = "mobile-more-item";
|
|
1318
|
+
themeBtn.innerHTML = '<i data-lucide="' + (isDark ? "sun" : "moon") + '"></i><span class="mobile-more-item-label">Switch to ' + (isDark ? "Light" : "Dark") + '</span>';
|
|
1319
|
+
|
|
1320
|
+
themeBtn.addEventListener("click", function () {
|
|
1321
|
+
var themeToggle = document.getElementById("theme-toggle-check");
|
|
1322
|
+
if (themeToggle) themeToggle.click();
|
|
1323
|
+
// Update button text after a tick (theme applies async)
|
|
1324
|
+
setTimeout(function () {
|
|
1325
|
+
var nowDark = getCurrentTheme().variant === "dark";
|
|
1326
|
+
themeBtn.innerHTML = '<i data-lucide="' + (nowDark ? "sun" : "moon") + '"></i><span class="mobile-more-item-label">Switch to ' + (nowDark ? "Light" : "Dark") + '</span>';
|
|
1327
|
+
refreshIcons();
|
|
1328
|
+
}, 50);
|
|
1329
|
+
});
|
|
1330
|
+
|
|
1331
|
+
listEl.appendChild(themeBtn);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
804
1334
|
export function initSidebar(_ctx) {
|
|
805
1335
|
ctx = _ctx;
|
|
806
1336
|
|
|
@@ -822,6 +1352,8 @@ export function initSidebar(_ctx) {
|
|
|
822
1352
|
|
|
823
1353
|
if (ctx.sidebarToggleBtn) ctx.sidebarToggleBtn.addEventListener("click", toggleSidebarCollapse);
|
|
824
1354
|
if (ctx.sidebarExpandBtn) ctx.sidebarExpandBtn.addEventListener("click", toggleSidebarCollapse);
|
|
1355
|
+
var mateSidebarToggle = document.getElementById("mate-sidebar-toggle-btn");
|
|
1356
|
+
if (mateSidebarToggle) mateSidebarToggle.addEventListener("click", toggleSidebarCollapse);
|
|
825
1357
|
|
|
826
1358
|
// Restore collapsed state from localStorage
|
|
827
1359
|
try {
|
|
@@ -980,6 +1512,83 @@ export function initSidebar(_ctx) {
|
|
|
980
1512
|
var sheetCloseBtn = mobileSheet.querySelector(".mobile-sheet-close");
|
|
981
1513
|
if (sheetBackdrop) sheetBackdrop.addEventListener("click", closeMobileSheet);
|
|
982
1514
|
if (sheetCloseBtn) sheetCloseBtn.addEventListener("click", closeMobileSheet);
|
|
1515
|
+
|
|
1516
|
+
// --- Drag to dismiss sheet ---
|
|
1517
|
+
var sheetHandle = mobileSheet.querySelector(".mobile-sheet-handle");
|
|
1518
|
+
var sheetContent = mobileSheet.querySelector(".mobile-sheet-content");
|
|
1519
|
+
if (sheetHandle && sheetContent) {
|
|
1520
|
+
var dragStartY = 0;
|
|
1521
|
+
var dragging = false;
|
|
1522
|
+
|
|
1523
|
+
sheetHandle.addEventListener("touchstart", function (e) {
|
|
1524
|
+
dragStartY = e.touches[0].clientY;
|
|
1525
|
+
dragging = true;
|
|
1526
|
+
sheetContent.style.transition = "none";
|
|
1527
|
+
}, { passive: true });
|
|
1528
|
+
|
|
1529
|
+
mobileSheet.addEventListener("touchmove", function (e) {
|
|
1530
|
+
if (!dragging) return;
|
|
1531
|
+
var deltaY = e.touches[0].clientY - dragStartY;
|
|
1532
|
+
if (deltaY < 0) deltaY = 0;
|
|
1533
|
+
sheetContent.style.transform = "translateY(" + deltaY + "px)";
|
|
1534
|
+
if (sheetBackdrop) {
|
|
1535
|
+
var opacity = Math.max(0, 1 - deltaY / (sheetContent.offsetHeight * 0.5));
|
|
1536
|
+
sheetBackdrop.style.opacity = opacity;
|
|
1537
|
+
}
|
|
1538
|
+
}, { passive: true });
|
|
1539
|
+
|
|
1540
|
+
mobileSheet.addEventListener("touchend", function () {
|
|
1541
|
+
if (!dragging) return;
|
|
1542
|
+
dragging = false;
|
|
1543
|
+
var currentY = parseFloat(sheetContent.style.transform.replace(/[^0-9.-]/g, "")) || 0;
|
|
1544
|
+
var threshold = sheetContent.offsetHeight * 0.3;
|
|
1545
|
+
|
|
1546
|
+
if (currentY > threshold) {
|
|
1547
|
+
sheetContent.style.transition = "transform 0.22s ease-in";
|
|
1548
|
+
sheetContent.style.transform = "translateY(100%)";
|
|
1549
|
+
if (sheetBackdrop) {
|
|
1550
|
+
sheetBackdrop.style.transition = "opacity 0.22s ease-in";
|
|
1551
|
+
sheetBackdrop.style.opacity = "0";
|
|
1552
|
+
}
|
|
1553
|
+
setTimeout(function () {
|
|
1554
|
+
sheetContent.style.transition = "";
|
|
1555
|
+
sheetContent.style.transform = "";
|
|
1556
|
+
if (sheetBackdrop) {
|
|
1557
|
+
sheetBackdrop.style.transition = "";
|
|
1558
|
+
sheetBackdrop.style.opacity = "";
|
|
1559
|
+
}
|
|
1560
|
+
// Close without animation since we already animated
|
|
1561
|
+
var sheet = document.getElementById("mobile-sheet");
|
|
1562
|
+
if (sheet) {
|
|
1563
|
+
if (sheet.classList.contains("sheet-files")) {
|
|
1564
|
+
var fileTree = document.getElementById("file-tree");
|
|
1565
|
+
var sidebarFilesPanel = document.getElementById("sidebar-panel-files");
|
|
1566
|
+
if (fileTree && sidebarFilesPanel) {
|
|
1567
|
+
sidebarFilesPanel.appendChild(fileTree);
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
sheet.classList.add("hidden");
|
|
1571
|
+
sheet.classList.remove("closing", "sheet-files");
|
|
1572
|
+
}
|
|
1573
|
+
}, 230);
|
|
1574
|
+
} else {
|
|
1575
|
+
sheetContent.style.transition = "transform 0.2s ease-out";
|
|
1576
|
+
sheetContent.style.transform = "translateY(0)";
|
|
1577
|
+
if (sheetBackdrop) {
|
|
1578
|
+
sheetBackdrop.style.transition = "opacity 0.2s ease-out";
|
|
1579
|
+
sheetBackdrop.style.opacity = "";
|
|
1580
|
+
}
|
|
1581
|
+
setTimeout(function () {
|
|
1582
|
+
sheetContent.style.transition = "";
|
|
1583
|
+
sheetContent.style.transform = "";
|
|
1584
|
+
if (sheetBackdrop) {
|
|
1585
|
+
sheetBackdrop.style.transition = "";
|
|
1586
|
+
sheetBackdrop.style.opacity = "";
|
|
1587
|
+
}
|
|
1588
|
+
}, 200);
|
|
1589
|
+
}
|
|
1590
|
+
}, { passive: true });
|
|
1591
|
+
}
|
|
983
1592
|
}
|
|
984
1593
|
|
|
985
1594
|
// --- Mobile tab bar ---
|
|
@@ -995,6 +1604,13 @@ export function initSidebar(_ctx) {
|
|
|
995
1604
|
mobileTabs[i].classList.remove("active");
|
|
996
1605
|
}
|
|
997
1606
|
}
|
|
1607
|
+
if (mobileHomeBtn) {
|
|
1608
|
+
if (tabName === "home") {
|
|
1609
|
+
mobileHomeBtn.classList.add("active");
|
|
1610
|
+
} else {
|
|
1611
|
+
mobileHomeBtn.classList.remove("active");
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
998
1614
|
}
|
|
999
1615
|
|
|
1000
1616
|
for (var t = 0; t < mobileTabs.length; t++) {
|
|
@@ -1002,22 +1618,18 @@ export function initSidebar(_ctx) {
|
|
|
1002
1618
|
tab.addEventListener("click", function () {
|
|
1003
1619
|
var name = tab.dataset.tab;
|
|
1004
1620
|
|
|
1005
|
-
if (name === "
|
|
1006
|
-
closeSidebar();
|
|
1007
|
-
setMobileTabActive("");
|
|
1008
|
-
if (ctx.openTerminal) ctx.openTerminal();
|
|
1009
|
-
return;
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
if (name === "projects") {
|
|
1013
|
-
openMobileSheet("projects");
|
|
1014
|
-
setMobileTabActive("projects");
|
|
1015
|
-
} else if (name === "sessions") {
|
|
1621
|
+
if (name === "chat") {
|
|
1016
1622
|
openMobileSheet("sessions");
|
|
1017
|
-
setMobileTabActive("
|
|
1018
|
-
} else if (name === "
|
|
1019
|
-
|
|
1020
|
-
setMobileTabActive("
|
|
1623
|
+
setMobileTabActive("chat");
|
|
1624
|
+
} else if (name === "search") {
|
|
1625
|
+
openCommandPalette();
|
|
1626
|
+
setMobileTabActive("search");
|
|
1627
|
+
} else if (name === "tools") {
|
|
1628
|
+
openMobileSheet("tools");
|
|
1629
|
+
setMobileTabActive("tools");
|
|
1630
|
+
} else if (name === "settings") {
|
|
1631
|
+
openMobileSheet("settings");
|
|
1632
|
+
setMobileTabActive("settings");
|
|
1021
1633
|
}
|
|
1022
1634
|
});
|
|
1023
1635
|
})(mobileTabs[t]);
|
|
@@ -1026,7 +1638,7 @@ export function initSidebar(_ctx) {
|
|
|
1026
1638
|
if (mobileHomeBtn) {
|
|
1027
1639
|
mobileHomeBtn.addEventListener("click", function () {
|
|
1028
1640
|
closeSidebar();
|
|
1029
|
-
setMobileTabActive("");
|
|
1641
|
+
setMobileTabActive("home");
|
|
1030
1642
|
if (ctx.showHomeHub) ctx.showHomeHub();
|
|
1031
1643
|
});
|
|
1032
1644
|
}
|
|
@@ -2634,7 +3246,12 @@ function createMobileProjectItem(p, currentSlug, isWorktree) {
|
|
|
2634
3246
|
|
|
2635
3247
|
var abbrev = document.createElement("span");
|
|
2636
3248
|
abbrev.className = "mobile-project-abbrev";
|
|
2637
|
-
|
|
3249
|
+
if (p.icon) {
|
|
3250
|
+
abbrev.textContent = p.icon;
|
|
3251
|
+
parseEmojis(abbrev);
|
|
3252
|
+
} else {
|
|
3253
|
+
abbrev.textContent = getProjectAbbrev(p.name);
|
|
3254
|
+
}
|
|
2638
3255
|
el.appendChild(abbrev);
|
|
2639
3256
|
|
|
2640
3257
|
var name = document.createElement("span");
|
|
@@ -2753,14 +3370,34 @@ export function renderUserStrip(allUsers, onlineUserIds, myUserId, dmFavorites,
|
|
|
2753
3370
|
})(others[i]);
|
|
2754
3371
|
}
|
|
2755
3372
|
|
|
3373
|
+
// Build mate project status lookup from project list
|
|
3374
|
+
var mateProjectStatus = {};
|
|
3375
|
+
if (ctx && ctx.projectList) {
|
|
3376
|
+
var allProjects = ctx.projectList;
|
|
3377
|
+
for (var pi = 0; pi < allProjects.length; pi++) {
|
|
3378
|
+
if (allProjects[pi].isMate) {
|
|
3379
|
+
mateProjectStatus[allProjects[pi].slug] = allProjects[pi];
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
|
|
2756
3384
|
// Render mates
|
|
2757
3385
|
for (var mi = 0; mi < cachedMates.length; mi++) {
|
|
2758
3386
|
(function (mate) {
|
|
2759
3387
|
var mp = mate.profile || {};
|
|
3388
|
+
var mateSlug = "mate-" + mate.id;
|
|
3389
|
+
var mateProj = mateProjectStatus[mateSlug] || {};
|
|
3390
|
+
var isActive = mate.id === currentDmUserId;
|
|
2760
3391
|
var el = document.createElement("div");
|
|
2761
3392
|
el.className = "icon-strip-user icon-strip-mate";
|
|
2762
3393
|
el.dataset.userId = mate.id;
|
|
2763
|
-
|
|
3394
|
+
el.dataset.mateSlug = mateSlug;
|
|
3395
|
+
if (isActive) el.classList.add("active");
|
|
3396
|
+
|
|
3397
|
+
// Pending permission shake
|
|
3398
|
+
if (mateProj.pendingPermissions > 0 && !isActive) {
|
|
3399
|
+
el.classList.add("has-pending-perm");
|
|
3400
|
+
}
|
|
2764
3401
|
|
|
2765
3402
|
var pill = document.createElement("span");
|
|
2766
3403
|
pill.className = "icon-strip-pill";
|
|
@@ -2772,6 +3409,12 @@ export function renderUserStrip(allUsers, onlineUserIds, myUserId, dmFavorites,
|
|
|
2772
3409
|
avatar.alt = mp.displayName || mate.name || "Mate";
|
|
2773
3410
|
el.appendChild(avatar);
|
|
2774
3411
|
|
|
3412
|
+
// Processing status dot (IO blink)
|
|
3413
|
+
var statusDot = document.createElement("span");
|
|
3414
|
+
statusDot.className = "icon-strip-status";
|
|
3415
|
+
if (mateProj.isProcessing) statusDot.classList.add("processing");
|
|
3416
|
+
el.appendChild(statusDot);
|
|
3417
|
+
|
|
2775
3418
|
// Mate badge (bot icon)
|
|
2776
3419
|
var mateBadge = document.createElement("span");
|
|
2777
3420
|
mateBadge.className = "icon-strip-user-mate-badge";
|
|
@@ -2783,6 +3426,13 @@ export function renderUserStrip(allUsers, onlineUserIds, myUserId, dmFavorites,
|
|
|
2783
3426
|
badge.dataset.userId = mate.id;
|
|
2784
3427
|
el.appendChild(badge);
|
|
2785
3428
|
|
|
3429
|
+
// Restore unread badge if cached
|
|
3430
|
+
var unreadCount = cachedDmUnread[mate.id] || 0;
|
|
3431
|
+
if (unreadCount > 0 && !isActive) {
|
|
3432
|
+
badge.textContent = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
3433
|
+
badge.classList.add("has-unread");
|
|
3434
|
+
}
|
|
3435
|
+
|
|
2786
3436
|
// Tooltip
|
|
2787
3437
|
var displayName = mp.displayName || mate.name || "New Mate";
|
|
2788
3438
|
el.addEventListener("mouseenter", function () { showIconTooltip(el, displayName); });
|