feat: Integrate Material UI theme provider and enhance UI components

This commit is contained in:
2026-01-31 15:36:55 +01:00
parent dc9def4faf
commit be6dc0de60
8 changed files with 222 additions and 139 deletions

View File

@@ -40,12 +40,11 @@ function CodeBlock({ code }) {
p: 2,
pr: 6,
bgcolor: "action.hover",
fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
fontFamily: "'Noto Sans Mono', monospace",
fontSize: "0.85rem",
whiteSpace: "pre-wrap",
wordBreak: "break-all",
position: "relative",
borderRadius: 2,
borderColor: "divider",
}}
>
@@ -92,10 +91,10 @@ function ApiKeyPage({
};
return (
<Box component="main" sx={{ flexGrow: 1, py: 4, px: 2 }}>
<Box sx={{ flexGrow: 1, py: 4, px: 2 }}>
<Grid container justifyContent="center">
<Grid size={{ xs: 12, md: 8, lg: 6 }}>
<Paper elevation={1} sx={{ p: { xs: 3, md: 5 }, borderRadius: 4, bgcolor: "background.paper", border: 1, borderColor: "divider" }}>
<Paper elevation={1} sx={{ p: { xs: 3, md: 5 }, bgcolor: "background.paper", border: 1, borderColor: "divider" }}>
<Typography variant="h5" gutterBottom sx={{ mb: 4, fontWeight: 700, display: "flex", alignItems: "center", gap: 1.5, color: "text.primary" }}>
<KeyIcon color="primary" /> API Key Management
</Typography>
@@ -111,11 +110,11 @@ function ApiKeyPage({
slotProps={{
input: {
readOnly: true,
style: { fontFamily: "'JetBrains Mono', 'Fira Code', monospace", fontSize: "0.9rem" },
style: { fontFamily: "'Noto Sans Mono', monospace", fontSize: "0.9rem" },
},
}}
variant="outlined"
sx={{ "& .MuiOutlinedInput-root": { borderRadius: 4, bgcolor: "background.paper" } }}
sx={{ "& .MuiOutlinedInput-root": { bgcolor: "background.paper" } }}
/>
<Tooltip title="Copy API Key">
<IconButton
@@ -156,7 +155,8 @@ function ApiKeyPage({
gap: 2,
}}
>
<Typography variant="h6" fontWeight="600" color="text.primary">📡 Remote Upload API</Typography>
<Typography variant="h6" fontWeight="600" color="text.primary">Remote Upload API</Typography>
<ToggleButtonGroup
size="small"
value={shellType}

View File

@@ -7,8 +7,7 @@ function Footer() {
<Box
component="footer"
sx={{
py: 2,
mt: 2,
py: 1,
borderTop: 1,
borderColor: "divider",
bgcolor: "background.paper",

View File

@@ -5,7 +5,6 @@ import {
Paper,
TextField,
Button,
Grid,
Tooltip,
IconButton,
Alert,
@@ -26,6 +25,7 @@ import {
Check as CheckIcon,
Refresh as RefreshIcon,
} from "@mui/icons-material";
import Grid from "@mui/material/Grid";
import jmespath from "jmespath";
function MainPage({
@@ -187,13 +187,23 @@ function MainPage({
};
return (
<Box component="main" sx={{ flexGrow: 1, py: 3, px: { xs: 2, md: 4 } }}>
<Box sx={{ mb: 4, maxWidth: 800, mx: "auto" }}>
<Box
sx={{
flexGrow: 1,
pt: 1,
pb: 3,
px: { xs: 2, md: 4 },
display: "flex",
flexDirection: "column",
minHeight: 0,
overflow: "hidden",
}}
>
<Box sx={{ mb: 2, flexShrink: 0 }}>
<Typography
variant="body1"
variant="body2"
color="text.secondary"
align="center"
sx={{ mb: 3 }}
align="left"
>
Validate and test JMESPath expressions against JSON data in real-time.
Enter your JMESPath query and JSON data below to see the results
@@ -203,166 +213,196 @@ function MainPage({
<Paper
sx={{
mb: 4,
p: 0,
borderRadius: 2,
overflow: "hidden",
mb: 3,
flexShrink: 0,
bgcolor: "background.paper",
p: 3,
border: 1,
borderColor: "divider",
}}
>
<Box
sx={{
px: 3,
py: 1.5,
display: "flex",
alignItems: "center",
gap: 1.5,
bgcolor: "action.hover",
justifyContent: "space-between",
mb: 2,
}}
>
<SearchIcon sx={{ fontSize: 24 }} color="primary" />
<Typography variant="subtitle1" fontWeight="600">
JMESPath Expression
</Typography>
</Box>
<Box sx={{ px: 3, pb: 2 }}>
<TextField
fullWidth
placeholder="Enter JMESPath expression (e.g., people[*].name)"
value={jmespathExpression}
onChange={handleJmespathChange}
error={!!error}
helperText={error || " "}
FormHelperTextProps={{
sx: { color: error ? "error.main" : "success.main", fontWeight: 500 }
}}
slotProps={{
input: {
style: { fontFamily: "'JetBrains Mono', 'Fira Code', monospace", fontSize: "1rem" },
},
}}
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: 3,
bgcolor: "background.paper",
}
}}
/>
{showReloadButton && (
<Box sx={{ display: "flex", justifyContent: "center", mt: -1, mb: 2 }}>
<Button
variant="contained"
color="secondary"
onClick={onReloadSampleData}
startIcon={<RefreshIcon />}
size="small"
>
New data available - Reload
</Button>
</Box>
)}
<Box sx={{ display: "flex", alignItems: "center", gap: 1.5 }}>
<SearchIcon sx={{ fontSize: 24 }} color="primary" />
<Typography variant="h6" fontWeight="600">
JMESPath Expression
</Typography>
</Box>
</Box>
<TextField
fullWidth
placeholder="Enter JMESPath expression (e.g., people[*].name)"
value={jmespathExpression}
onChange={handleJmespathChange}
error={!!error}
helperText={error || " "}
sx={{
"& .MuiInputBase-root": {
fontFamily: "'Noto Sans Mono', monospace",
fontSize: "1.1rem",
},
}}
/>
</Paper>
<Grid container spacing={3} sx={{ flexGrow: 1, minHeight: 0 }}>
<Grid size={{ xs: 12, md: 6 }} sx={{ display: "flex", flexDirection: "column" }}>
<Grid container spacing={3} sx={{ flex: "1 1 0", minHeight: 0, height: 0 }}>
<Grid size={{ xs: 12, md: 6 }} sx={{ display: "flex", flexDirection: "column", minHeight: 0 }}>
<Paper
sx={{
flexGrow: 1,
display: "flex",
flexDirection: "column",
borderRadius: 4,
overflow: "hidden",
bgcolor: "background.paper",
border: 1,
borderColor: "divider",
minHeight: 0,
}}
>
<Box
sx={{
px: 2,
py: 2,
py: 1.5,
bgcolor: "action.hover",
borderBottom: 1,
borderColor: "divider",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
flexWrap: "wrap",
gap: 1,
}}
>
<Box sx={{ display: "flex", alignItems: "center" }}>
<DataObjectIcon sx={{ mr: 1, fontSize: 20 }} color="primary" />
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<DataObjectIcon sx={{ fontSize: 20 }} color="primary" />
<Typography variant="subtitle2" color="text.primary">
JSON Input
</Typography>
{showReloadButton && (
<Button
variant="contained"
color="secondary"
onClick={onReloadSampleData}
startIcon={<RefreshIcon fontSize="inherit" />}
size="small"
sx={{
ml: 1,
px: 1,
py: 0.25,
fontSize: "0.65rem",
textTransform: "none",
whiteSpace: "nowrap",
minWidth: "auto",
}}
>
Reload data
</Button>
)}
</Box>
<Stack direction="row" spacing={1} flexWrap="wrap">
<Stack direction="row" spacing={1} alignItems="center">
<Tooltip title="Load from Disk">
<span>
<IconButton size="medium" onClick={loadFromDisk} color="primary" aria-label="Load from Disk">
<FileOpenIcon fontSize="small" />
</IconButton>
</span>
<IconButton
size="small"
onClick={loadFromDisk}
color="primary"
aria-label="Load from Disk"
>
<FileOpenIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Load Logs">
<span>
<IconButton size="medium" onClick={loadLogFile} color="primary" aria-label="Load Logs">
<UploadFileIcon fontSize="small" />
</IconButton>
</span>
<IconButton
size="small"
onClick={loadLogFile}
color="primary"
aria-label="Load Logs"
>
<UploadFileIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Load Sample">
<span>
<IconButton size="medium" onClick={loadSample} color="primary" aria-label="Load Sample">
<RestoreIcon fontSize="small" />
</IconButton>
</span>
<IconButton
size="small"
onClick={loadSample}
color="primary"
aria-label="Load Sample"
>
<RestoreIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Format">
<span>
<IconButton size="medium" onClick={formatJson} color="primary" aria-label="Format">
<FormatAlignLeftIcon fontSize="small" />
</IconButton>
</span>
<IconButton
size="small"
onClick={formatJson}
color="primary"
aria-label="Format"
>
<FormatAlignLeftIcon fontSize="small" />
</IconButton>
</Tooltip>
<Divider orientation="vertical" flexItem sx={{ mx: 0.5 }} />
<Tooltip title="Clear">
<span>
<IconButton size="medium" onClick={clearAll} color="secondary" aria-label="Clear all inputs">
<ClearIcon fontSize="small" />
</IconButton>
</span>
<Tooltip title="Clear all inputs">
<IconButton
size="small"
onClick={clearAll}
color="secondary"
aria-label="Clear all inputs"
>
<ClearIcon fontSize="small" />
</IconButton>
</Tooltip>
</Stack>
</Box>
<Box sx={{ p: 2, flexGrow: 1, display: "flex", flexDirection: "column" }}>
<Box sx={{ p: 2, flex: "1 1 0", display: "flex", flexDirection: "column", minHeight: 0, overflow: "hidden" }}>
<TextField
multiline
fullWidth
value={jsonData}
onChange={handleJsonChange}
placeholder="Enter JSON data here..."
error={!!jsonError}
variant="standard"
slotProps={{
input: {
disableUnderline: true,
style: {
fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
height: "100%",
alignItems: "flex-start",
fontSize: "0.85rem",
lineHeight: 1.5,
height: "100%",
boxSizing: "border-box",
},
},
}}
sx={{
flexGrow: 1,
"& .MuiInputBase-root": { height: "100%", overflow: "auto" },
flex: "1 1 0",
display: "flex",
flexDirection: "column",
height: 0,
minHeight: 0,
"& .MuiInputBase-root": {
flex: "1 1 0",
display: "flex",
flexDirection: "column",
alignItems: "stretch",
height: "100%",
minHeight: 0,
},
"& .MuiInputBase-input": {
flexGrow: 1,
overflow: "auto !important",
height: "100% !important",
resize: "none",
padding: 0,
},
}}
/>
{jsonError && (
<Alert severity="error" sx={{ mt: 1, borderRadius: 2 }} variant="filled">
<Alert severity="error" sx={{ mt: 1, flexShrink: 0 }} variant="filled">
{jsonError}
</Alert>
)}
@@ -370,21 +410,23 @@ function MainPage({
</Paper>
</Grid>
<Grid size={{ xs: 12, md: 6 }} sx={{ display: "flex", flexDirection: "column" }}>
<Grid size={{ xs: 12, md: 6 }} sx={{ display: "flex", flexDirection: "column", minHeight: 0 }}>
<Paper
sx={{
flexGrow: 1,
display: "flex",
flexDirection: "column",
borderRadius: 4,
overflow: "hidden",
bgcolor: "background.paper",
border: 1,
borderColor: "divider",
minHeight: 0,
}}
>
<Box
sx={{
px: 2,
py: 2,
py: 1.5,
bgcolor: "action.hover",
borderBottom: 1,
borderColor: "divider",
@@ -403,7 +445,7 @@ function MainPage({
<Tooltip title="Copy to Clipboard">
<span>
<IconButton
size="medium"
size="small"
onClick={copyToClipboard}
disabled={!result || result === "null"}
color={copySuccess ? "success" : "primary"}
@@ -415,7 +457,7 @@ function MainPage({
<Tooltip title="Download Result">
<span>
<IconButton
size="medium"
size="small"
onClick={downloadResult}
disabled={!result || result === "null"}
color="primary"
@@ -426,29 +468,47 @@ function MainPage({
</Tooltip>
</Stack>
</Box>
<Box sx={{ p: 2, flexGrow: 1, display: "flex", flexDirection: "column" }}>
<Box sx={{ p: 2, flex: "1 1 0", display: "flex", flexDirection: "column", minHeight: 0, overflow: "hidden" }}>
<TextField
multiline
fullWidth
value={result}
variant="standard"
placeholder="Results will appear here..."
slotProps={{
input: {
readOnly: true,
disableUnderline: true,
style: {
fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
height: "100%",
alignItems: "flex-start",
fontSize: "0.85rem",
lineHeight: 1.5,
height: "100%",
boxSizing: "border-box",
},
},
}}
variant="standard"
placeholder="Results will appear here..."
sx={{
flexGrow: 1,
"& .MuiInputBase-root": { height: "100%", overflow: "auto" },
flex: "1 1 0",
display: "flex",
flexDirection: "column",
height: 0,
minHeight: 0,
"& .MuiInputBase-root": {
flex: "1 1 0",
display: "flex",
flexDirection: "column",
alignItems: "stretch",
height: "100%",
minHeight: 0,
},
"& .MuiInputBase-input": {
flexGrow: 1,
overflow: "auto !important",
height: "100% !important",
resize: "none",
padding: 0,
},
}}
/>
</Box>