Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
555017a
fix tailwind config
CodyKoInABox Jun 30, 2025
6b02005
better UI
CodyKoInABox Jun 30, 2025
f3a1de7
stop using tailwind since it doesnt work
CodyKoInABox Jun 30, 2025
ec975f9
make colors dune themed
CodyKoInABox Jun 30, 2025
8e45fa3
make text more readable
CodyKoInABox Jun 30, 2025
fd61d04
go logo png
CodyKoInABox Jun 30, 2025
5316f41
js logo png
CodyKoInABox Jun 30, 2025
52560ba
py logo png
CodyKoInABox Jun 30, 2025
cd0422b
ruby logo png
CodyKoInABox Jun 30, 2025
e5463a1
generic file icon
CodyKoInABox Jun 30, 2025
6b5e480
file type helper func
CodyKoInABox Jun 30, 2025
e3116d9
use file type icons instead of emojis
CodyKoInABox Jun 30, 2025
0dd7da0
fix python logo
CodyKoInABox Jun 30, 2025
eab7601
fix go logo
CodyKoInABox Jun 30, 2025
6d52f2e
api endpoint to return all analyzed files
CodyKoInABox Jun 30, 2025
331cc9c
use new api endpoint
CodyKoInABox Jun 30, 2025
21dd669
fix file logos not showing up correctly
CodyKoInABox Jun 30, 2025
bc41321
change header title
CodyKoInABox Jun 30, 2025
3493c1e
spicecode logo
CodyKoInABox Jun 30, 2025
059aad1
add spicecode logo to header
CodyKoInABox Jun 30, 2025
f8553d6
utils file
CodyKoInABox Jun 30, 2025
3a456e3
use data util
CodyKoInABox Jun 30, 2025
be15180
types util
CodyKoInABox Jun 30, 2025
7f6d3c6
styles
CodyKoInABox Jun 30, 2025
7fb4895
metrics grid component
CodyKoInABox Jun 30, 2025
5804984
metric card component
CodyKoInABox Jun 30, 2025
9e36966
method type component
CodyKoInABox Jun 30, 2025
f86407e
loading spinner component
CodyKoInABox Jun 30, 2025
25e2d96
indentation card component
CodyKoInABox Jun 30, 2025
925da08
header component
CodyKoInABox Jun 30, 2025
44849e2
file list component
CodyKoInABox Jun 30, 2025
28fb8b6
file header component
CodyKoInABox Jun 30, 2025
13c3549
empty state component
CodyKoInABox Jun 30, 2025
bb0787c
separate page into componnets
CodyKoInABox Jun 30, 2025
cda9b8e
tab title and favicon
CodyKoInABox Jun 30, 2025
525cf84
remove title from _document to avoid warning
CodyKoInABox Jun 30, 2025
3bc82a7
add title to _app to follow new nextjs docs guidelines
CodyKoInABox Jun 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion spicecloud/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import Head from 'next/head'
import React from 'react'

export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
return (
<>
<Head>
<title>SpiceCloud | Powered by SpiceCodeCLI</title>
</Head>

<Component {...pageProps} />
</>
)

}
4 changes: 3 additions & 1 deletion spicecloud/pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html lang="en">
<Head />
<Head>
<link rel="icon" href="/spicecode-logo.png" />
</Head>
<body className="antialiased">
<Main />
<NextScript />
Expand Down
15 changes: 15 additions & 0 deletions spicecloud/pages/api/files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// pages/api/files.ts
import { promises as fs } from 'fs';
import path from 'path';

export default async function handler(req: any, res: { status: (arg0: number) => { (): any; new(): any; json: { (arg0: { error: string; }): void; new(): any; }; }; }) {
try {
const filePath = path.join(process.cwd(), 'data', 'metrics.json');
const fileContent = await fs.readFile(filePath, 'utf-8');
const jsonData = JSON.parse(fileContent);
res.status(200).json(jsonData);
} catch (err) {
console.error('Erro ao ler metrics.json', err);
res.status(500).json({ error: 'Failed to load metrics.json' });
}
}
13 changes: 13 additions & 0 deletions spicecloud/pages/components/EmptyState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { styles } from '../utils/styles';

export const EmptyState: React.FC = () => {
return (
<div style={styles.emptyState}>
<div style={styles.emptyStateContent}>
<div style={styles.emptyStateIcon}>👆</div>
<p style={styles.emptyStateText}>Select a file from the sidebar to view its metrics</p>
</div>
</div>
);
};
36 changes: 36 additions & 0 deletions spicecloud/pages/components/FileHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { MetricData } from '../utils/types';
import { getFileIconSrc } from '../utils/utils';
import { styles } from '../utils/styles';

interface FileHeaderProps {
selectedFile: MetricData;
}

export const FileHeader: React.FC<FileHeaderProps> = ({ selectedFile }) => {
return (
<div style={styles.fileHeader}>
<div style={styles.fileHeaderContent}>
<div style={styles.fileHeaderIcon}>
<img
src={getFileIconSrc(selectedFile.metrics.file_extension)}
alt={selectedFile.metrics.file_extension}
style={styles.fileHeaderImg}
/>
</div>

<div style={{ flex: 1 }}>
<h2 style={styles.fileHeaderTitle}>{selectedFile.file_name}</h2>
<p style={styles.fileHeaderPath} title={selectedFile.file_path}>
📁 {selectedFile.file_path}
</p>
<div style={styles.fileHeaderMeta}>
<span>🕒 {selectedFile.readable_timestamp}</span>
<span>💾 {selectedFile.metrics.file_size ? `${(selectedFile.metrics.file_size / 1024).toFixed(1)} KB` : 'N/A'}</span>
<span>📂 {selectedFile.metrics.file_extension || 'N/A'}</span>
</div>
</div>
</div>
</div>
);
};
69 changes: 69 additions & 0 deletions spicecloud/pages/components/FileList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';
import { MetricData } from '../utils/types';
import { getFileIconSrc, formatAge } from '../utils/utils';
import { styles } from '../utils/styles';

interface FileListProps {
data: MetricData[];
selectedFile: MetricData | null;
onFileSelect: (file: MetricData) => void;
}

export const FileList: React.FC<FileListProps> = ({ data, selectedFile, onFileSelect }) => {
return (
<div style={styles.sidebar}>
<h2 style={styles.sidebarTitle}>
<span>📁</span>
Analyzed Files
</h2>
<div style={styles.fileList}>
{data.map((item) => (
<div
key={item.id}
onClick={() => onFileSelect(item)}
style={{
...styles.fileItem,
...(selectedFile?.id === item.id
? styles.fileItemSelected
: styles.fileItemDefault)
}}
className="file-item"
onMouseEnter={(e) => {
if (selectedFile?.id !== item.id) {
e.currentTarget.style.background = 'rgba(255, 255, 255, 0.1)';
}
}}
onMouseLeave={(e) => {
if (selectedFile?.id !== item.id) {
e.currentTarget.style.background = 'rgba(255, 255, 255, 0.05)';
}
}}
>
<div style={styles.fileInfo}>
<div style={styles.fileIcon}>
<img
src={getFileIconSrc(item.metrics.file_extension)}
alt={item.metrics.file_extension}
style={styles.fileIconImg}
/>
</div>

<div style={{ flex: 1, minWidth: 0 }}>
<div style={styles.fileName} title={item.file_name}>
{item.file_name}
</div>
<div style={styles.filePath} title={item.file_path}>
{item.file_path.replace(item.file_name, '')}
</div>
<div style={styles.fileAge}>
<span>🕒</span>
{formatAge(item.age)}
</div>
</div>
</div>
</div>
))}
</div>
</div>
);
};
38 changes: 38 additions & 0 deletions spicecloud/pages/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import { styles } from '../utils/styles';

interface HeaderProps {
dataLength: number;
loading: boolean;
onRefresh: () => void;
}

export const Header: React.FC<HeaderProps> = ({ dataLength, loading, onRefresh }) => {
return (
<div style={styles.header}>
<div style={styles.headerContent}>
<div>
<h1 style={styles.title}>
<img
src="/spicecode-logo.png"
alt="SpiceCode Logo"
style={{ width: '3rem', height: '3rem', verticalAlign: 'middle', marginRight: '0.5rem' }}
/>
SpiceCloud | Powered by SpiceCodeCLI
</h1>
<p style={styles.subtitle}>{dataLength} files analyzed</p>
</div>
<button
onClick={onRefresh}
disabled={loading}
style={{
...styles.refreshButton,
background: loading ? '#bfa865' : '#d97304'
}}
>
{loading ? '🔄 Updating...' : '🔄 Refresh'}
</button>
</div>
</div>
);
};
35 changes: 35 additions & 0 deletions spicecloud/pages/components/IndentationCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { styles } from '../utils/styles';

interface IndentationCardProps {
indentationType?: string;
indentationSize?: number;
}

export const IndentationCard: React.FC<IndentationCardProps> = ({
indentationType,
indentationSize
}) => {
return (
<div style={{ ...styles.metricCard, ...styles.indentationCard }} className="metric-card">
<div style={styles.metricHeader}>
<span style={styles.metricIcon} className="metric-icon">📐</span>
<h3 style={styles.metricTitle}>Indentation</h3>
</div>
<div style={styles.indentationList}>
<div style={styles.indentationItem}>
<span style={styles.indentationLabel}>Type:</span>
<span style={styles.indentationValue}>
{indentationType || 'N/A'}
</span>
</div>
<div style={styles.indentationItem}>
<span style={styles.indentationLabel}>Size:</span>
<span style={styles.indentationValue}>
{indentationSize || 'N/A'}
</span>
</div>
</div>
</div>
);
};
13 changes: 13 additions & 0 deletions spicecloud/pages/components/LoadingSpinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { styles } from '../utils/styles';

export const LoadingSpinner: React.FC = () => {
return (
<div style={styles.loading}>
<div style={{ textAlign: 'center' }}>
<div style={styles.loadingSpinner}></div>
<p style={{ marginTop: '1.5rem', fontSize: '1.125rem' }}>Loading your code metrics...</p>
</div>
</div>
);
};
39 changes: 39 additions & 0 deletions spicecloud/pages/components/MethodTypeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { styles } from '../utils/styles';

interface MethodTypeCardProps {
value: {
public: number;
private: number;
};
}

export const MethodTypeCard: React.FC<MethodTypeCardProps> = ({ value }) => {
return (
<div
style={{ ...styles.metricCard, ...styles.methodTypeCard }}
className="metric-card"
>
<div style={styles.metricHeader}>
<span style={styles.metricIcon} className="metric-icon">🔧</span>
<h3 style={styles.metricTitle}>Method Types</h3>
</div>
<div style={styles.methodTypeList}>
<div style={styles.methodTypeItem}>
<div style={styles.methodTypeLabel}>
<span style={{ ...styles.methodTypeDot, background: '#10b981' }}></span>
<span style={styles.methodTypeText}>Public</span>
</div>
<span style={styles.methodTypeValue}>{value.public}</span>
</div>
<div style={styles.methodTypeItem}>
<div style={styles.methodTypeLabel}>
<span style={{ ...styles.methodTypeDot, background: '#3b82f6' }}></span>
<span style={styles.methodTypeText}>Private</span>
</div>
<span style={styles.methodTypeValue}>{value.private}</span>
</div>
</div>
</div>
);
};
48 changes: 48 additions & 0 deletions spicecloud/pages/components/MetricCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { formatMetricValue, getMetricIcon, getMetricColor, formatLabel } from '../utils/utils';
import { styles } from '../utils/styles';

interface MetricCardProps {
metricKey: string;
value: any;
}

export const MetricCard: React.FC<MetricCardProps> = ({ metricKey, value }) => {
return (
<div
style={{
...styles.metricCard,
background: getMetricColor(metricKey).replace('135deg', '135deg') + '20'
}}
className="metric-card"
onMouseEnter={(e) => {
e.currentTarget.style.transform = 'scale(1.05)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.transform = 'scale(1)';
}}
>
<div style={styles.metricHeader}>
<span style={styles.metricIcon} className="metric-icon">
{getMetricIcon(metricKey)}
</span>
<h3 style={styles.metricTitle}>
{formatLabel(metricKey)}
</h3>
</div>
<div style={styles.metricValue}>
{formatMetricValue(metricKey, value)}
</div>
{metricKey.includes('ratio') && (
<div style={styles.progressBar}>
<div
style={{
...styles.progressFill,
width: `${Math.min((value as number) * 100, 100)}%`
}}
></div>
</div>
)}
</div>
);
};
Loading