repo-wrapped 0.0.6 ā 0.0.7
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/SPECS.md +490 -0
- package/dist/commands/generate.js +262 -5
- package/dist/generators/html/styles/base.css +2 -3
- package/dist/generators/html/styles/leaddev.css +1275 -0
- package/dist/generators/html/templates/comparisonSection.js +119 -0
- package/dist/generators/html/templates/eventsSection.js +113 -0
- package/dist/generators/html/templates/executiveSummarySection.js +84 -0
- package/dist/generators/html/templates/gapSection.js +190 -0
- package/dist/generators/html/templates/teamSection.js +146 -0
- package/dist/generators/html/templates/velocitySection.js +189 -0
- package/dist/generators/html/utils/styleLoader.js +2 -1
- package/dist/index.js +33 -0
- package/dist/utils/eventAnnotationParser.js +253 -0
- package/dist/utils/executiveSummaryGenerator.js +275 -0
- package/dist/utils/gapAnalyzer.js +300 -0
- package/dist/utils/htmlGenerator.js +103 -23
- package/dist/utils/rangeComparisonAnalyzer.js +222 -0
- package/dist/utils/teamAnalyzer.js +297 -0
- package/dist/utils/velocityAnalyzer.js +252 -0
- package/package.json +11 -2
- package/test-team.txt +2 -0
|
@@ -46,6 +46,16 @@ const path = __importStar(require("path"));
|
|
|
46
46
|
const gitParser_1 = require("../utils/gitParser");
|
|
47
47
|
const htmlGenerator_1 = require("../utils/htmlGenerator");
|
|
48
48
|
const matrixGenerator_1 = require("../utils/matrixGenerator");
|
|
49
|
+
const velocityAnalyzer_1 = require("../utils/velocityAnalyzer");
|
|
50
|
+
const gapAnalyzer_1 = require("../utils/gapAnalyzer");
|
|
51
|
+
const rangeComparisonAnalyzer_1 = require("../utils/rangeComparisonAnalyzer");
|
|
52
|
+
const teamAnalyzer_1 = require("../utils/teamAnalyzer");
|
|
53
|
+
const executiveSummaryGenerator_1 = require("../utils/executiveSummaryGenerator");
|
|
54
|
+
const eventAnnotationParser_1 = require("../utils/eventAnnotationParser");
|
|
55
|
+
const streakCalculator_1 = require("../utils/streakCalculator");
|
|
56
|
+
const timePatternAnalyzer_1 = require("../utils/timePatternAnalyzer");
|
|
57
|
+
const commitQualityAnalyzer_1 = require("../utils/commitQualityAnalyzer");
|
|
58
|
+
const knowledgeDistributionAnalyzer_1 = require("../utils/knowledgeDistributionAnalyzer");
|
|
49
59
|
async function generateMatrix(repoPath, options) {
|
|
50
60
|
const spinner = (0, ora_1.default)('Analyzing git repository...').start();
|
|
51
61
|
try {
|
|
@@ -57,19 +67,167 @@ async function generateMatrix(repoPath, options) {
|
|
|
57
67
|
process.exit(1);
|
|
58
68
|
}
|
|
59
69
|
spinner.text = 'Fetching commit history...';
|
|
60
|
-
|
|
70
|
+
let commits = (0, gitParser_1.parseGitCommits)(absolutePath);
|
|
61
71
|
if (commits.length === 0) {
|
|
62
72
|
spinner.warn(chalk_1.default.yellow('No commits found in the repository.'));
|
|
63
73
|
return;
|
|
64
74
|
}
|
|
75
|
+
// Apply author filtering if specified
|
|
76
|
+
const authorFilter = (0, teamAnalyzer_1.parseAuthorFilter)(options.author, options.authors, options.excludeAuthor, options.excludeAuthors);
|
|
77
|
+
if (authorFilter) {
|
|
78
|
+
spinner.text = 'Filtering commits by author...';
|
|
79
|
+
commits = (0, teamAnalyzer_1.filterCommitsByAuthor)(commits, authorFilter);
|
|
80
|
+
if (commits.length === 0) {
|
|
81
|
+
spinner.warn(chalk_1.default.yellow('No commits found matching the author filter.'));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Load team file if specified
|
|
86
|
+
let teamMembers;
|
|
87
|
+
if (options.team) {
|
|
88
|
+
try {
|
|
89
|
+
teamMembers = (0, teamAnalyzer_1.loadTeamFile)(options.team);
|
|
90
|
+
spinner.text = `Loaded ${teamMembers.length} team members`;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
spinner.fail(chalk_1.default.red(error.message));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Load events if specified
|
|
98
|
+
let events;
|
|
99
|
+
if (options.events) {
|
|
100
|
+
try {
|
|
101
|
+
const eventsConfig = (0, eventAnnotationParser_1.loadEventsFile)(options.events);
|
|
102
|
+
events = eventsConfig.events;
|
|
103
|
+
spinner.text = `Loaded ${events.length} event annotations`;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
spinner.fail(chalk_1.default.red(error.message));
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
65
110
|
spinner.text = 'Generating visualization...';
|
|
111
|
+
// Calculate date range
|
|
112
|
+
const commitDates = commits.map(c => new Date(c.date));
|
|
113
|
+
const dataStartDate = new Date(Math.min(...commitDates.map(d => d.getTime())));
|
|
114
|
+
const dataEndDate = new Date(Math.max(...commitDates.map(d => d.getTime())));
|
|
115
|
+
const skipBodyCheck = !options.bodyCheck;
|
|
116
|
+
const repoName = (0, gitParser_1.getRepositoryName)(absolutePath);
|
|
117
|
+
// Handle --summary-only mode (implies --executive-summary)
|
|
118
|
+
if (options.summaryOnly) {
|
|
119
|
+
const deepAnalysis = options.deepAnalysis ?? false;
|
|
120
|
+
const windowWeeks = options.velocityWindow ? parseInt(options.velocityWindow) : 4;
|
|
121
|
+
const gapThreshold = options.gapThreshold ? parseInt(options.gapThreshold) : 3;
|
|
122
|
+
const streaks = (0, streakCalculator_1.calculateStreaks)(commits, dataStartDate, dataEndDate);
|
|
123
|
+
const timePatterns = (0, timePatternAnalyzer_1.analyzeTimePatterns)(commits, dataStartDate, dataEndDate);
|
|
124
|
+
const quality = (0, commitQualityAnalyzer_1.analyzeCommitQuality)(commits, { skipBodyCheck });
|
|
125
|
+
const knowledge = (0, knowledgeDistributionAnalyzer_1.analyzeKnowledgeDistribution)(commits, absolutePath, deepAnalysis);
|
|
126
|
+
const velocityAnalysis = (0, velocityAnalyzer_1.analyzeVelocity)(commits, dataStartDate, dataEndDate, windowWeeks);
|
|
127
|
+
const gapAnalysis = (0, gapAnalyzer_1.analyzeGaps)(commits, dataStartDate, dataEndDate, gapThreshold);
|
|
128
|
+
const summary = (0, executiveSummaryGenerator_1.generateExecutiveSummary)({
|
|
129
|
+
commits,
|
|
130
|
+
repoName,
|
|
131
|
+
streakData: streaks,
|
|
132
|
+
timePattern: timePatterns,
|
|
133
|
+
commitQuality: quality,
|
|
134
|
+
velocityAnalysis,
|
|
135
|
+
gapAnalysis,
|
|
136
|
+
knowledgeDistribution: knowledge,
|
|
137
|
+
startDate: dataStartDate,
|
|
138
|
+
endDate: dataEndDate
|
|
139
|
+
});
|
|
140
|
+
if (options.html) {
|
|
141
|
+
// Generate summary-only HTML
|
|
142
|
+
const html = (0, htmlGenerator_1.generateSummaryOnlyHTML)(summary, repoName);
|
|
143
|
+
const outputPath = path.join(os.tmpdir(), `executive-summary-${Date.now()}.html`);
|
|
144
|
+
fs.writeFileSync(outputPath, html);
|
|
145
|
+
spinner.succeed(chalk_1.default.green('Executive Summary generated!'));
|
|
146
|
+
console.log();
|
|
147
|
+
console.log(chalk_1.default.cyan('Opening in browser...'));
|
|
148
|
+
console.log(chalk_1.default.dim(`File: ${outputPath}`));
|
|
149
|
+
const command = process.platform === 'win32'
|
|
150
|
+
? `start "" "${outputPath}"`
|
|
151
|
+
: process.platform === 'darwin'
|
|
152
|
+
? `open "${outputPath}"`
|
|
153
|
+
: `xdg-open "${outputPath}"`;
|
|
154
|
+
(0, child_process_1.exec)(command);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// Terminal-only executive summary
|
|
158
|
+
spinner.succeed(chalk_1.default.green('Executive Summary'));
|
|
159
|
+
console.log();
|
|
160
|
+
for (const line of (0, executiveSummaryGenerator_1.formatExecutiveSummary)(summary)) {
|
|
161
|
+
console.log(line);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Check if we need terminal-only lead dev insights (no HTML)
|
|
167
|
+
const needsLeadDevInsights = options.velocity || options.gapAnalysis ||
|
|
168
|
+
options.compare || options.executiveSummary || teamMembers || events;
|
|
66
169
|
if (options.html) {
|
|
67
170
|
// Generate HTML output
|
|
68
171
|
const repoName = (0, gitParser_1.getRepositoryName)(absolutePath);
|
|
69
172
|
const repoUrl = (0, gitParser_1.getRepositoryUrl)(absolutePath);
|
|
70
|
-
const skipBodyCheck = !options.bodyCheck;
|
|
71
173
|
const deepAnalysis = options.deepAnalysis ?? false;
|
|
72
|
-
|
|
174
|
+
// Build lead dev options if requested
|
|
175
|
+
let leadDevOptions;
|
|
176
|
+
if (options.velocity || options.gapAnalysis || options.compare || options.executiveSummary || teamMembers || events) {
|
|
177
|
+
leadDevOptions = {};
|
|
178
|
+
const windowWeeks = options.velocityWindow ? parseInt(options.velocityWindow) : 4;
|
|
179
|
+
const gapThreshold = options.gapThreshold ? parseInt(options.gapThreshold) : 3;
|
|
180
|
+
if (options.velocity) {
|
|
181
|
+
leadDevOptions.velocityAnalysis = (0, velocityAnalyzer_1.analyzeVelocity)(commits, dataStartDate, dataEndDate, windowWeeks);
|
|
182
|
+
}
|
|
183
|
+
if (options.gapAnalysis) {
|
|
184
|
+
leadDevOptions.gapAnalysis = (0, gapAnalyzer_1.analyzeGaps)(commits, dataStartDate, dataEndDate, gapThreshold);
|
|
185
|
+
}
|
|
186
|
+
if (options.compare && options.compare.length >= 2) {
|
|
187
|
+
const range1 = (0, rangeComparisonAnalyzer_1.parseDateRange)(options.compare[0]);
|
|
188
|
+
const range2 = (0, rangeComparisonAnalyzer_1.parseDateRange)(options.compare[1]);
|
|
189
|
+
if (range1 && range2) {
|
|
190
|
+
const labelsList = options.compareLabels
|
|
191
|
+
? options.compareLabels.split(',').map(l => l.trim())
|
|
192
|
+
: ['Period 1', 'Period 2'];
|
|
193
|
+
leadDevOptions.rangeComparison = (0, rangeComparisonAnalyzer_1.compareRanges)(commits, range1.start, range1.end, range2.start, range2.end, labelsList[0], labelsList[1] || 'Period 2', skipBodyCheck);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (teamMembers && teamMembers.length > 0) {
|
|
197
|
+
leadDevOptions.teamAnalysis = (0, teamAnalyzer_1.analyzeTeam)(commits, teamMembers, undefined, skipBodyCheck);
|
|
198
|
+
}
|
|
199
|
+
// Add events with correlations
|
|
200
|
+
if (events && events.length > 0) {
|
|
201
|
+
leadDevOptions.events = (0, eventAnnotationParser_1.correlateEventsWithMetrics)(events, commits, 14, skipBodyCheck);
|
|
202
|
+
}
|
|
203
|
+
if (options.executiveSummary) {
|
|
204
|
+
const streaks = (0, streakCalculator_1.calculateStreaks)(commits, dataStartDate, dataEndDate);
|
|
205
|
+
const timePatterns = (0, timePatternAnalyzer_1.analyzeTimePatterns)(commits, dataStartDate, dataEndDate);
|
|
206
|
+
const quality = (0, commitQualityAnalyzer_1.analyzeCommitQuality)(commits, { skipBodyCheck });
|
|
207
|
+
const knowledge = (0, knowledgeDistributionAnalyzer_1.analyzeKnowledgeDistribution)(commits, absolutePath, deepAnalysis);
|
|
208
|
+
let velocityForSummary = leadDevOptions.velocityAnalysis;
|
|
209
|
+
if (!velocityForSummary) {
|
|
210
|
+
velocityForSummary = (0, velocityAnalyzer_1.analyzeVelocity)(commits, dataStartDate, dataEndDate, windowWeeks);
|
|
211
|
+
}
|
|
212
|
+
let gapForSummary = leadDevOptions.gapAnalysis;
|
|
213
|
+
if (!gapForSummary) {
|
|
214
|
+
gapForSummary = (0, gapAnalyzer_1.analyzeGaps)(commits, dataStartDate, dataEndDate, gapThreshold);
|
|
215
|
+
}
|
|
216
|
+
leadDevOptions.executiveSummary = (0, executiveSummaryGenerator_1.generateExecutiveSummary)({
|
|
217
|
+
commits,
|
|
218
|
+
repoName,
|
|
219
|
+
streakData: streaks,
|
|
220
|
+
timePattern: timePatterns,
|
|
221
|
+
commitQuality: quality,
|
|
222
|
+
velocityAnalysis: velocityForSummary,
|
|
223
|
+
gapAnalysis: gapForSummary,
|
|
224
|
+
knowledgeDistribution: knowledge,
|
|
225
|
+
startDate: dataStartDate,
|
|
226
|
+
endDate: dataEndDate
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const html = (0, htmlGenerator_1.generateHTML)(commits, year, monthsToShow, absolutePath, repoName, repoUrl, skipBodyCheck, options.all, deepAnalysis, leadDevOptions);
|
|
73
231
|
const outputPath = path.join(os.tmpdir(), `git-wrapped-${Date.now()}.html`);
|
|
74
232
|
fs.writeFileSync(outputPath, html);
|
|
75
233
|
spinner.succeed(chalk_1.default.green('HTML file generated successfully!'));
|
|
@@ -84,8 +242,105 @@ async function generateMatrix(repoPath, options) {
|
|
|
84
242
|
: `xdg-open "${outputPath}"`;
|
|
85
243
|
(0, child_process_1.exec)(command);
|
|
86
244
|
}
|
|
245
|
+
else if (needsLeadDevInsights) {
|
|
246
|
+
// Generate lead developer insights in terminal
|
|
247
|
+
spinner.succeed(chalk_1.default.green('ā Analysis complete!'));
|
|
248
|
+
console.log();
|
|
249
|
+
// Range comparison
|
|
250
|
+
if (options.compare && options.compare.length >= 2) {
|
|
251
|
+
const range1 = (0, rangeComparisonAnalyzer_1.parseDateRange)(options.compare[0]);
|
|
252
|
+
const range2 = (0, rangeComparisonAnalyzer_1.parseDateRange)(options.compare[1]);
|
|
253
|
+
if (!range1 || !range2) {
|
|
254
|
+
console.log(chalk_1.default.red('Invalid date range format. Use: YYYY-MM-DD..YYYY-MM-DD'));
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
const labelsList = options.compareLabels
|
|
258
|
+
? options.compareLabels.split(',').map(l => l.trim())
|
|
259
|
+
: ['Period 1', 'Period 2'];
|
|
260
|
+
const comparison = (0, rangeComparisonAnalyzer_1.compareRanges)(commits, range1.start, range1.end, range2.start, range2.end, labelsList[0], labelsList[1] || 'Period 2', skipBodyCheck);
|
|
261
|
+
console.log(chalk_1.default.bold.cyan('\nš RANGE COMPARISON'));
|
|
262
|
+
console.log(chalk_1.default.dim('ā'.repeat(60)));
|
|
263
|
+
for (const line of (0, rangeComparisonAnalyzer_1.formatComparisonInsights)(comparison)) {
|
|
264
|
+
console.log(line);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Velocity analysis
|
|
269
|
+
if (options.velocity) {
|
|
270
|
+
const velocityWindow = parseInt(options.velocityWindow || '4');
|
|
271
|
+
const velocity = (0, velocityAnalyzer_1.analyzeVelocity)(commits, dataStartDate, dataEndDate, velocityWindow);
|
|
272
|
+
console.log(chalk_1.default.bold.cyan('\nš VELOCITY ANALYSIS'));
|
|
273
|
+
console.log(chalk_1.default.dim('ā'.repeat(60)));
|
|
274
|
+
for (const line of (0, velocityAnalyzer_1.formatVelocityInsights)(velocity)) {
|
|
275
|
+
console.log(line);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Gap analysis
|
|
279
|
+
if (options.gapAnalysis) {
|
|
280
|
+
const gapThreshold = parseInt(options.gapThreshold || '3');
|
|
281
|
+
const gaps = (0, gapAnalyzer_1.analyzeGaps)(commits, dataStartDate, dataEndDate, gapThreshold);
|
|
282
|
+
console.log(chalk_1.default.bold.cyan('\nš³ļø GAP ANALYSIS'));
|
|
283
|
+
console.log(chalk_1.default.dim('ā'.repeat(60)));
|
|
284
|
+
for (const line of (0, gapAnalyzer_1.formatGapInsights)(gaps)) {
|
|
285
|
+
console.log(line);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// Team analysis
|
|
289
|
+
if (teamMembers) {
|
|
290
|
+
const teamAnalysis = (0, teamAnalyzer_1.analyzeTeam)(commits, teamMembers, undefined, skipBodyCheck);
|
|
291
|
+
console.log(chalk_1.default.bold.cyan('\nš„ TEAM ANALYSIS'));
|
|
292
|
+
console.log(chalk_1.default.dim('ā'.repeat(60)));
|
|
293
|
+
for (const line of (0, teamAnalyzer_1.formatTeamInsights)(teamAnalysis)) {
|
|
294
|
+
console.log(line);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// Events analysis
|
|
298
|
+
if (events) {
|
|
299
|
+
const correlatedEvents = (0, eventAnnotationParser_1.correlateEventsWithMetrics)(events, commits, 14, skipBodyCheck);
|
|
300
|
+
console.log(chalk_1.default.bold.cyan('\nš
EVENT ANNOTATIONS'));
|
|
301
|
+
console.log(chalk_1.default.dim('ā'.repeat(60)));
|
|
302
|
+
for (const line of (0, eventAnnotationParser_1.formatEventsInsights)(correlatedEvents)) {
|
|
303
|
+
console.log(line);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Executive summary (last, as it summarizes everything)
|
|
307
|
+
if (options.executiveSummary) {
|
|
308
|
+
const repoName = (0, gitParser_1.getRepositoryName)(absolutePath);
|
|
309
|
+
const streakData = (0, streakCalculator_1.calculateStreaks)(commits, dataStartDate, dataEndDate);
|
|
310
|
+
const timePattern = (0, timePatternAnalyzer_1.analyzeTimePatterns)(commits, dataStartDate, dataEndDate);
|
|
311
|
+
const commitQuality = (0, commitQualityAnalyzer_1.analyzeCommitQuality)(commits, { skipBodyCheck });
|
|
312
|
+
const knowledgeDistribution = (0, knowledgeDistributionAnalyzer_1.analyzeKnowledgeDistribution)(commits, absolutePath, false);
|
|
313
|
+
let velocity, gaps;
|
|
314
|
+
if (options.velocity) {
|
|
315
|
+
const velocityWindow = parseInt(options.velocityWindow || '4');
|
|
316
|
+
velocity = (0, velocityAnalyzer_1.analyzeVelocity)(commits, dataStartDate, dataEndDate, velocityWindow);
|
|
317
|
+
}
|
|
318
|
+
if (options.gapAnalysis) {
|
|
319
|
+
const gapThreshold = parseInt(options.gapThreshold || '3');
|
|
320
|
+
gaps = (0, gapAnalyzer_1.analyzeGaps)(commits, dataStartDate, dataEndDate, gapThreshold);
|
|
321
|
+
}
|
|
322
|
+
const summary = (0, executiveSummaryGenerator_1.generateExecutiveSummary)({
|
|
323
|
+
commits,
|
|
324
|
+
startDate: dataStartDate,
|
|
325
|
+
endDate: dataEndDate,
|
|
326
|
+
repoName,
|
|
327
|
+
streakData,
|
|
328
|
+
timePattern,
|
|
329
|
+
commitQuality,
|
|
330
|
+
knowledgeDistribution,
|
|
331
|
+
velocityAnalysis: velocity,
|
|
332
|
+
gapAnalysis: gaps,
|
|
333
|
+
});
|
|
334
|
+
console.log(chalk_1.default.bold.cyan('\n'));
|
|
335
|
+
for (const line of (0, executiveSummaryGenerator_1.formatExecutiveSummary)(summary)) {
|
|
336
|
+
console.log(line);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
console.log();
|
|
340
|
+
console.log(chalk_1.default.cyan('š” Tip:'), chalk_1.default.dim('Add'), chalk_1.default.white('--html'), chalk_1.default.dim('for interactive HTML report'));
|
|
341
|
+
}
|
|
87
342
|
else {
|
|
88
|
-
// Generate terminal output
|
|
343
|
+
// Generate terminal output (default)
|
|
89
344
|
const repoName = (0, gitParser_1.getRepositoryName)(absolutePath);
|
|
90
345
|
const repoUrl = (0, gitParser_1.getRepositoryUrl)(absolutePath);
|
|
91
346
|
const matrix = (0, matrixGenerator_1.generateCommitMatrix)(commits, year, monthsToShow, absolutePath, repoName, repoUrl);
|
|
@@ -93,7 +348,9 @@ async function generateMatrix(repoPath, options) {
|
|
|
93
348
|
console.log(matrix);
|
|
94
349
|
console.log();
|
|
95
350
|
console.log(chalk_1.default.cyan('š” Tip:'), chalk_1.default.dim('Run with'), chalk_1.default.white('--html'), chalk_1.default.dim('to see interactive details and per-developer analytics'));
|
|
96
|
-
console.log(chalk_1.default.dim(' Example:'), chalk_1.default.white(`
|
|
351
|
+
console.log(chalk_1.default.dim(' Example:'), chalk_1.default.white(`repo-wrapped generate ${repoPath} --html`));
|
|
352
|
+
console.log();
|
|
353
|
+
console.log(chalk_1.default.cyan('š Lead Dev:'), chalk_1.default.dim('Try'), chalk_1.default.white('--velocity --gap-analysis --executive-summary'), chalk_1.default.dim('for management insights'));
|
|
97
354
|
}
|
|
98
355
|
}
|
|
99
356
|
catch (error) {
|
|
@@ -130,7 +130,7 @@ body {
|
|
|
130
130
|
border: 1px solid var(--border-default);
|
|
131
131
|
border-radius: var(--radius-lg);
|
|
132
132
|
padding: var(--spacing-lg);
|
|
133
|
-
|
|
133
|
+
min-width: 70vw;
|
|
134
134
|
box-shadow: var(--shadow-md);
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -547,7 +547,6 @@ h3 {
|
|
|
547
547
|
.sidebar-header {
|
|
548
548
|
padding: var(--spacing-md);
|
|
549
549
|
margin-bottom: var(--spacing-md);
|
|
550
|
-
border-bottom: 1px solid var(--border-default);
|
|
551
550
|
display: flex;
|
|
552
551
|
align-items: center;
|
|
553
552
|
justify-content: space-between;
|
|
@@ -662,7 +661,7 @@ h3 {
|
|
|
662
661
|
/* === Main Content === */
|
|
663
662
|
.main-content {
|
|
664
663
|
flex: 1;
|
|
665
|
-
min-width:
|
|
664
|
+
min-width: 70vw;
|
|
666
665
|
}
|
|
667
666
|
|
|
668
667
|
/* === Dashboard Section (Collapsible) === */
|