claude-code-templates 1.21.10 → 1.21.11
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/package.json +1 -1
- package/src/analytics-web/chats_mobile.html +338 -14
- package/src/analytics.js +1 -32
- package/src/test-activity-data.json +0 -1094
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-templates",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.11",
|
|
4
4
|
"description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -81,6 +81,26 @@
|
|
|
81
81
|
width: 100%;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
.chat-header-content .header-left {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
flex: 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.chat-header-content .header-center {
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
flex: 0 0 auto;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.chat-header-content .header-right {
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
justify-content: flex-end;
|
|
101
|
+
flex: 1;
|
|
102
|
+
}
|
|
103
|
+
|
|
84
104
|
.chat-title {
|
|
85
105
|
font-size: 1.2rem;
|
|
86
106
|
font-weight: 700;
|
|
@@ -770,9 +790,30 @@
|
|
|
770
790
|
border-bottom: 1px solid var(--border-primary);
|
|
771
791
|
display: flex;
|
|
772
792
|
align-items: center;
|
|
793
|
+
justify-content: space-between;
|
|
773
794
|
min-height: 64px;
|
|
774
795
|
}
|
|
775
796
|
|
|
797
|
+
.header-left {
|
|
798
|
+
display: flex;
|
|
799
|
+
align-items: center;
|
|
800
|
+
flex: 1;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
.header-center {
|
|
804
|
+
display: flex;
|
|
805
|
+
align-items: center;
|
|
806
|
+
justify-content: center;
|
|
807
|
+
flex: 0 0 auto;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.header-right {
|
|
811
|
+
display: flex;
|
|
812
|
+
align-items: center;
|
|
813
|
+
justify-content: flex-end;
|
|
814
|
+
flex: 1;
|
|
815
|
+
}
|
|
816
|
+
|
|
776
817
|
.chat-view-back {
|
|
777
818
|
margin-right: 16px;
|
|
778
819
|
}
|
|
@@ -997,6 +1038,136 @@
|
|
|
997
1038
|
/* On larger screens, show side-by-side if needed */
|
|
998
1039
|
}
|
|
999
1040
|
}
|
|
1041
|
+
/* Modal styles */
|
|
1042
|
+
.modal-overlay {
|
|
1043
|
+
position: fixed;
|
|
1044
|
+
top: 0;
|
|
1045
|
+
left: 0;
|
|
1046
|
+
width: 100%;
|
|
1047
|
+
height: 100%;
|
|
1048
|
+
background: rgba(0, 0, 0, 0.8);
|
|
1049
|
+
display: none;
|
|
1050
|
+
justify-content: center;
|
|
1051
|
+
align-items: center;
|
|
1052
|
+
z-index: 1000;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.modal-overlay.show {
|
|
1056
|
+
display: flex;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.modal {
|
|
1060
|
+
background: var(--bg-secondary);
|
|
1061
|
+
border-radius: 12px;
|
|
1062
|
+
border: 1px solid var(--border-primary);
|
|
1063
|
+
padding: 24px;
|
|
1064
|
+
max-width: 600px;
|
|
1065
|
+
width: 95%;
|
|
1066
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
|
1067
|
+
animation: modalSlideIn 0.3s ease-out;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
@keyframes modalSlideIn {
|
|
1071
|
+
from {
|
|
1072
|
+
opacity: 0;
|
|
1073
|
+
transform: translateY(-20px) scale(0.95);
|
|
1074
|
+
}
|
|
1075
|
+
to {
|
|
1076
|
+
opacity: 1;
|
|
1077
|
+
transform: translateY(0) scale(1);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
.modal-header {
|
|
1082
|
+
display: flex;
|
|
1083
|
+
align-items: center;
|
|
1084
|
+
margin-bottom: 16px;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
.modal-icon {
|
|
1088
|
+
font-size: 1.5rem;
|
|
1089
|
+
margin-right: 12px;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
.modal-title {
|
|
1093
|
+
font-size: 1.2rem;
|
|
1094
|
+
font-weight: 700;
|
|
1095
|
+
color: var(--text-primary);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
.modal-description {
|
|
1099
|
+
color: var(--text-secondary);
|
|
1100
|
+
font-size: 0.9rem;
|
|
1101
|
+
margin-bottom: 20px;
|
|
1102
|
+
line-height: 1.4;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
.modal-command {
|
|
1106
|
+
background: var(--bg-tertiary);
|
|
1107
|
+
border: 1px solid var(--border-primary);
|
|
1108
|
+
border-radius: 8px;
|
|
1109
|
+
padding: 12px;
|
|
1110
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
1111
|
+
font-size: 0.85rem;
|
|
1112
|
+
color: var(--terminal-orange);
|
|
1113
|
+
word-break: break-all;
|
|
1114
|
+
margin-bottom: 20px;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
.modal-actions {
|
|
1118
|
+
display: flex;
|
|
1119
|
+
gap: 12px;
|
|
1120
|
+
justify-content: flex-end;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
.modal-btn {
|
|
1124
|
+
background: rgba(255, 107, 53, 0.1);
|
|
1125
|
+
border: 1px solid rgba(255, 107, 53, 0.2);
|
|
1126
|
+
color: var(--terminal-orange);
|
|
1127
|
+
font-size: 0.85rem;
|
|
1128
|
+
font-weight: 600;
|
|
1129
|
+
cursor: pointer;
|
|
1130
|
+
padding: 8px 16px;
|
|
1131
|
+
border-radius: 8px;
|
|
1132
|
+
transition: all 0.2s ease;
|
|
1133
|
+
text-transform: uppercase;
|
|
1134
|
+
letter-spacing: 0.5px;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
.modal-btn:hover {
|
|
1138
|
+
background: rgba(255, 107, 53, 0.15);
|
|
1139
|
+
border-color: rgba(255, 107, 53, 0.3);
|
|
1140
|
+
transform: translateY(-1px);
|
|
1141
|
+
box-shadow: 0 2px 4px rgba(255, 107, 53, 0.2);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
.modal-btn:active {
|
|
1145
|
+
transform: translateY(0);
|
|
1146
|
+
box-shadow: 0 1px 2px rgba(255, 107, 53, 0.2);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
.modal-btn.primary {
|
|
1150
|
+
background: var(--terminal-orange);
|
|
1151
|
+
color: var(--bg-primary);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
.modal-btn.primary:hover {
|
|
1155
|
+
background: var(--terminal-orange-hover);
|
|
1156
|
+
color: var(--bg-primary);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
.modal-btn.secondary {
|
|
1160
|
+
background: transparent;
|
|
1161
|
+
border-color: var(--border-primary);
|
|
1162
|
+
color: var(--text-secondary);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.modal-btn.secondary:hover {
|
|
1166
|
+
background: var(--bg-tertiary);
|
|
1167
|
+
border-color: var(--border-secondary);
|
|
1168
|
+
color: var(--text-primary);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1000
1171
|
</style>
|
|
1001
1172
|
</head>
|
|
1002
1173
|
<body>
|
|
@@ -1006,8 +1177,15 @@
|
|
|
1006
1177
|
<!-- Header -->
|
|
1007
1178
|
<div class="chat-header">
|
|
1008
1179
|
<div class="chat-header-content">
|
|
1009
|
-
<
|
|
1010
|
-
|
|
1180
|
+
<div class="header-left">
|
|
1181
|
+
<h1 class="chat-title">Claude Code Chats</h1>
|
|
1182
|
+
</div>
|
|
1183
|
+
<div class="header-center">
|
|
1184
|
+
<button class="header-btn" id="githubBtn" title="Star on GitHub" onclick="window.open('https://github.com/davila7/claude-code-templates', '_blank')">
|
|
1185
|
+
⭐️ on Github
|
|
1186
|
+
</button>
|
|
1187
|
+
</div>
|
|
1188
|
+
<div class="header-right">
|
|
1011
1189
|
<button class="header-btn" id="refreshBtn" title="Refresh">
|
|
1012
1190
|
Refresh
|
|
1013
1191
|
</button>
|
|
@@ -1034,19 +1212,28 @@
|
|
|
1034
1212
|
<!-- Chat View -->
|
|
1035
1213
|
<div class="chat-view" id="chatView">
|
|
1036
1214
|
<div class="chat-view-header">
|
|
1037
|
-
<
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
<
|
|
1042
|
-
|
|
1215
|
+
<div class="header-left">
|
|
1216
|
+
<button class="header-btn back-btn chat-view-back" id="backToList">
|
|
1217
|
+
←
|
|
1218
|
+
</button>
|
|
1219
|
+
<div class="chat-view-info">
|
|
1220
|
+
<h2 class="chat-view-title" id="chatViewTitle">Select a conversation</h2>
|
|
1221
|
+
<p class="chat-view-subtitle" id="chatViewSubtitle"></p>
|
|
1222
|
+
</div>
|
|
1223
|
+
</div>
|
|
1224
|
+
<div class="header-center">
|
|
1225
|
+
<button class="header-btn resume-btn" id="resumeConversation" style="display: none;" onclick="resumeConversationWithClaude()">
|
|
1226
|
+
▶️ Resume
|
|
1227
|
+
</button>
|
|
1043
1228
|
</div>
|
|
1044
|
-
<div class="
|
|
1045
|
-
<
|
|
1046
|
-
|
|
1047
|
-
<
|
|
1048
|
-
|
|
1049
|
-
|
|
1229
|
+
<div class="header-right">
|
|
1230
|
+
<div class="tools-toggle" id="toolsToggle">
|
|
1231
|
+
<span class="tools-toggle-label" onclick="document.getElementById('showToolsSwitch').click()">Show Tools</span>
|
|
1232
|
+
<label class="toggle-switch">
|
|
1233
|
+
<input type="checkbox" id="showToolsSwitch" checked>
|
|
1234
|
+
<span class="toggle-slider"></span>
|
|
1235
|
+
</label>
|
|
1236
|
+
</div>
|
|
1050
1237
|
</div>
|
|
1051
1238
|
</div>
|
|
1052
1239
|
<div class="chat-messages" id="chatMessages">
|
|
@@ -1068,6 +1255,26 @@
|
|
|
1068
1255
|
</div>
|
|
1069
1256
|
</div>
|
|
1070
1257
|
|
|
1258
|
+
<!-- Resume Conversation Modal -->
|
|
1259
|
+
<div class="modal-overlay" id="resumeModal">
|
|
1260
|
+
<div class="modal">
|
|
1261
|
+
<div class="modal-header">
|
|
1262
|
+
<span class="modal-icon">▶️</span>
|
|
1263
|
+
<h3 class="modal-title">Resume Conversation</h3>
|
|
1264
|
+
</div>
|
|
1265
|
+
<p class="modal-description">
|
|
1266
|
+
To resume this conversation in Claude Code, copy and run the following command in your terminal:
|
|
1267
|
+
</p>
|
|
1268
|
+
<div class="modal-command" id="modalCommand">
|
|
1269
|
+
<!-- Command will be inserted here -->
|
|
1270
|
+
</div>
|
|
1271
|
+
<div class="modal-actions">
|
|
1272
|
+
<button class="modal-btn secondary" onclick="closeResumeModal()">Cancel</button>
|
|
1273
|
+
<button class="modal-btn primary" id="copyCommandBtn" onclick="copyModalCommand()">Copy Command</button>
|
|
1274
|
+
</div>
|
|
1275
|
+
</div>
|
|
1276
|
+
</div>
|
|
1277
|
+
|
|
1071
1278
|
<!-- Import WebSocket and Data Services -->
|
|
1072
1279
|
<script src="services/WebSocketService.js"></script>
|
|
1073
1280
|
<script src="services/DataService.js"></script>
|
|
@@ -1308,6 +1515,11 @@
|
|
|
1308
1515
|
chatView.classList.remove('show-tools');
|
|
1309
1516
|
}
|
|
1310
1517
|
|
|
1518
|
+
// Show resume button
|
|
1519
|
+
const resumeBtn = document.getElementById('resumeConversation');
|
|
1520
|
+
resumeBtn.style.display = 'block';
|
|
1521
|
+
resumeBtn.setAttribute('data-conversation-id', conversationId);
|
|
1522
|
+
|
|
1311
1523
|
// Load messages (placeholder for now)
|
|
1312
1524
|
this.loadChatMessages(conversationId);
|
|
1313
1525
|
}
|
|
@@ -1320,6 +1532,10 @@
|
|
|
1320
1532
|
|
|
1321
1533
|
// Clean up scroll tracking when leaving conversation
|
|
1322
1534
|
this.removeScrollTracking();
|
|
1535
|
+
|
|
1536
|
+
// Hide resume button
|
|
1537
|
+
const resumeBtn = document.getElementById('resumeConversation');
|
|
1538
|
+
resumeBtn.style.display = 'none';
|
|
1323
1539
|
|
|
1324
1540
|
// Remove active state from conversations
|
|
1325
1541
|
document.querySelectorAll('.conversation-item').forEach(item => {
|
|
@@ -2581,6 +2797,114 @@
|
|
|
2581
2797
|
}
|
|
2582
2798
|
}
|
|
2583
2799
|
|
|
2800
|
+
// Global function to resume conversation with Claude Code
|
|
2801
|
+
function resumeConversationWithClaude() {
|
|
2802
|
+
const resumeBtn = document.getElementById('resumeConversation');
|
|
2803
|
+
const conversationId = resumeBtn.getAttribute('data-conversation-id');
|
|
2804
|
+
|
|
2805
|
+
if (!conversationId) {
|
|
2806
|
+
console.error('No conversation ID found');
|
|
2807
|
+
return;
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
// Show modal with command
|
|
2811
|
+
showResumeModal(conversationId);
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
function showResumeModal(conversationId) {
|
|
2815
|
+
const modal = document.getElementById('resumeModal');
|
|
2816
|
+
const modalCommand = document.getElementById('modalCommand');
|
|
2817
|
+
const command = `claude --resume ${conversationId}`;
|
|
2818
|
+
|
|
2819
|
+
// Set the command in the modal
|
|
2820
|
+
modalCommand.textContent = command;
|
|
2821
|
+
modalCommand.setAttribute('data-command', command);
|
|
2822
|
+
|
|
2823
|
+
// Show the modal
|
|
2824
|
+
modal.classList.add('show');
|
|
2825
|
+
|
|
2826
|
+
// Close modal when clicking outside
|
|
2827
|
+
modal.addEventListener('click', (e) => {
|
|
2828
|
+
if (e.target === modal) {
|
|
2829
|
+
closeResumeModal();
|
|
2830
|
+
}
|
|
2831
|
+
});
|
|
2832
|
+
|
|
2833
|
+
console.log('📋 Resume modal opened for conversation:', conversationId);
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
function closeResumeModal() {
|
|
2837
|
+
const modal = document.getElementById('resumeModal');
|
|
2838
|
+
modal.classList.remove('show');
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
function copyModalCommand() {
|
|
2842
|
+
const modalCommand = document.getElementById('modalCommand');
|
|
2843
|
+
const copyBtn = document.getElementById('copyCommandBtn');
|
|
2844
|
+
const command = modalCommand.getAttribute('data-command');
|
|
2845
|
+
|
|
2846
|
+
if (!command) {
|
|
2847
|
+
console.error('No command found to copy');
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
2852
|
+
navigator.clipboard.writeText(command).then(() => {
|
|
2853
|
+
// Show success feedback
|
|
2854
|
+
const originalText = copyBtn.textContent;
|
|
2855
|
+
copyBtn.textContent = '✅ Copied!';
|
|
2856
|
+
copyBtn.style.backgroundColor = 'rgba(63, 185, 80, 0.8)';
|
|
2857
|
+
copyBtn.style.borderColor = 'rgba(63, 185, 80, 1)';
|
|
2858
|
+
|
|
2859
|
+
setTimeout(() => {
|
|
2860
|
+
copyBtn.textContent = originalText;
|
|
2861
|
+
copyBtn.style.backgroundColor = '';
|
|
2862
|
+
copyBtn.style.borderColor = '';
|
|
2863
|
+
closeResumeModal();
|
|
2864
|
+
}, 1500);
|
|
2865
|
+
|
|
2866
|
+
console.log('📋 Command copied to clipboard:', command);
|
|
2867
|
+
}).catch(err => {
|
|
2868
|
+
console.error('Failed to copy to clipboard:', err);
|
|
2869
|
+
fallbackCopy(command);
|
|
2870
|
+
});
|
|
2871
|
+
} else {
|
|
2872
|
+
// Fallback for browsers without clipboard API
|
|
2873
|
+
fallbackCopy(command);
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
function fallbackCopy(command) {
|
|
2878
|
+
// Create a temporary text area to select and copy
|
|
2879
|
+
const tempTextArea = document.createElement('textarea');
|
|
2880
|
+
tempTextArea.value = command;
|
|
2881
|
+
tempTextArea.style.position = 'fixed';
|
|
2882
|
+
tempTextArea.style.left = '-9999px';
|
|
2883
|
+
document.body.appendChild(tempTextArea);
|
|
2884
|
+
tempTextArea.select();
|
|
2885
|
+
|
|
2886
|
+
try {
|
|
2887
|
+
document.execCommand('copy');
|
|
2888
|
+
const copyBtn = document.getElementById('copyCommandBtn');
|
|
2889
|
+
const originalText = copyBtn.textContent;
|
|
2890
|
+
copyBtn.textContent = '✅ Copied!';
|
|
2891
|
+
copyBtn.style.backgroundColor = 'rgba(63, 185, 80, 0.8)';
|
|
2892
|
+
|
|
2893
|
+
setTimeout(() => {
|
|
2894
|
+
copyBtn.textContent = originalText;
|
|
2895
|
+
copyBtn.style.backgroundColor = '';
|
|
2896
|
+
closeResumeModal();
|
|
2897
|
+
}, 1500);
|
|
2898
|
+
|
|
2899
|
+
console.log('📋 Command copied using fallback method:', command);
|
|
2900
|
+
} catch (err) {
|
|
2901
|
+
console.error('Fallback copy failed:', err);
|
|
2902
|
+
alert(`Please copy this command manually:\n\n${command}`);
|
|
2903
|
+
} finally {
|
|
2904
|
+
document.body.removeChild(tempTextArea);
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2584
2908
|
// Initialize the app
|
|
2585
2909
|
document.addEventListener('DOMContentLoaded', () => {
|
|
2586
2910
|
new ChatsMobileApp();
|
package/src/analytics.js
CHANGED
|
@@ -1227,41 +1227,10 @@ class ClaudeAnalytics {
|
|
|
1227
1227
|
// Activity heatmap data endpoint - needs full conversation history
|
|
1228
1228
|
this.app.get('/api/activity', async (req, res) => {
|
|
1229
1229
|
try {
|
|
1230
|
-
// TEMPORARY: Use test data for demo/screenshots
|
|
1231
|
-
console.log(`🔥 /api/activity called - using test data for demo...`);
|
|
1232
|
-
const fs = require('fs');
|
|
1233
|
-
const path = require('path');
|
|
1234
|
-
const testDataPath = path.join(__dirname, 'test-activity-data.json');
|
|
1235
|
-
|
|
1236
|
-
if (fs.existsSync(testDataPath)) {
|
|
1237
|
-
const testData = JSON.parse(fs.readFileSync(testDataPath, 'utf8'));
|
|
1238
|
-
|
|
1239
|
-
// Calculate totals
|
|
1240
|
-
const totalContributions = testData.reduce((sum, day) => sum + day.conversations, 0);
|
|
1241
|
-
const totalTools = testData.reduce((sum, day) => sum + day.tools, 0);
|
|
1242
|
-
const totalMessages = testData.reduce((sum, day) => sum + day.messages, 0);
|
|
1243
|
-
const totalTokens = testData.reduce((sum, day) => sum + day.tokens, 0);
|
|
1244
|
-
|
|
1245
|
-
const activityData = {
|
|
1246
|
-
dailyActivity: testData,
|
|
1247
|
-
totalContributions,
|
|
1248
|
-
activeDays: testData.length,
|
|
1249
|
-
longestStreak: 7, // Sample streak
|
|
1250
|
-
currentStreak: 3, // Sample current streak
|
|
1251
|
-
totalTools,
|
|
1252
|
-
totalMessages,
|
|
1253
|
-
totalTokens,
|
|
1254
|
-
timestamp: new Date().toISOString()
|
|
1255
|
-
};
|
|
1256
|
-
|
|
1257
|
-
return res.json(activityData);
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
// Fallback to real data if test file doesn't exist
|
|
1261
1230
|
console.log(`🔥 /api/activity called - loading all conversations...`);
|
|
1262
1231
|
const allConversations = await this.conversationAnalyzer.loadConversations(this.stateCalculator);
|
|
1263
1232
|
console.log(`🔥 Loaded ${allConversations.length} conversations from server`);
|
|
1264
|
-
|
|
1233
|
+
|
|
1265
1234
|
// Generate activity data using complete dataset
|
|
1266
1235
|
const activityData = this.generateActivityDataFromConversations(allConversations);
|
|
1267
1236
|
res.json({
|