Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.

Commit b913115

Browse files
committed
feat: copy, download, and preview
1 parent eec3277 commit b913115

File tree

3 files changed

+229
-63
lines changed

3 files changed

+229
-63
lines changed
Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,86 @@
1-
.App {
2-
text-align: center;
1+
/* App.css */
2+
3+
body {
4+
background-color: #f5f5f5;
35
}
46

5-
.App-logo {
6-
height: 40vmin;
7-
pointer-events: none;
7+
.container {
8+
padding: 2rem 0;
89
}
910

10-
@media (prefers-reduced-motion: no-preference) {
11-
.App-logo {
12-
animation: App-logo-spin infinite 20s linear;
13-
}
11+
.paper {
12+
padding: 2rem;
1413
}
1514

16-
.App-header {
17-
background-color: #282c34;
18-
min-height: 100vh;
15+
.header {
1916
display: flex;
20-
flex-direction: column;
17+
justify-content: space-between;
2118
align-items: center;
19+
margin-bottom: 2rem;
20+
}
21+
22+
.title {
23+
font-size: 2rem;
24+
font-weight: bold;
25+
}
26+
27+
.action-buttons {
28+
display: flex;
2229
justify-content: center;
23-
font-size: calc(10px + 2vmin);
24-
color: white;
30+
gap: 1rem;
31+
margin-top: 2rem;
32+
}
33+
34+
.form-section {
35+
margin-top: 2rem;
36+
}
37+
38+
.modal-content {
39+
position: absolute;
40+
top: 50%;
41+
left: 50%;
42+
transform: translate(-50%, -50%);
43+
width: 80%;
44+
max-width: 800px;
45+
max-height: 80vh;
46+
overflow-y: auto;
47+
background-color: white;
48+
padding: 2rem;
49+
border-radius: 4px;
50+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
2551
}
2652

27-
.App-link {
28-
color: #61dafb;
53+
.code-preview {
54+
background-color: #f5f5f5;
55+
padding: 1rem;
56+
border-radius: 4px;
57+
font-family: 'Courier New', Courier, monospace;
58+
font-size: 0.9rem;
59+
line-height: 1.5;
60+
white-space: pre-wrap;
61+
word-break: break-word;
62+
max-height: calc(80vh - 120px);
63+
overflow-y: auto;
2964
}
3065

31-
@keyframes App-logo-spin {
32-
from {
33-
transform: rotate(0deg);
66+
@media (max-width: 600px) {
67+
.header {
68+
flex-direction: column;
69+
align-items: flex-start;
70+
}
71+
72+
.action-buttons {
73+
flex-direction: column;
74+
align-items: stretch;
75+
gap: 0.5rem;
76+
}
77+
78+
.modal-content {
79+
width: 95%;
80+
padding: 1rem;
3481
}
35-
to {
36-
transform: rotate(360deg);
82+
83+
.code-preview {
84+
font-size: 0.8rem;
3785
}
3886
}

examples/context-editor/src/App.tsx

Lines changed: 123 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,128 @@
11
import React, { useState } from 'react';
2-
import { Container, Paper, Modal, Box, Button, Typography, Tabs, Tab, Link as MuiLink } from '@mui/material';
2+
import { Container, Paper, Modal, Box, Button, Typography, Tabs, Tab, Link as MuiLink, Tooltip, IconButton, Snackbar } from '@mui/material';
33
import { ThemeProvider } from '@mui/material/styles';
44
import DescriptionIcon from '@mui/icons-material/Description';
55
import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
66
import BlockIcon from '@mui/icons-material/Block';
7+
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
8+
import DownloadIcon from '@mui/icons-material/Download';
9+
import PreviewIcon from '@mui/icons-material/Visibility';
10+
import CloseIcon from '@mui/icons-material/Close';
711
import { BrowserRouter as Router, Routes, Route, Link, useLocation } from 'react-router-dom';
812
import theme from './theme';
913
import ContextForm from './components/ContextForm';
1014
import ContextDocsForm from './components/ContextDocsForm';
1115
import ContextIgnoreForm from './components/ContextIgnoreForm';
16+
import './App.css';
1217

1318
// Conditional base path for GitHub Pages
1419
const BASE_PATH = process.env.NODE_ENV === 'production' ? '/codebase-context-spec' : '';
1520

1621
const App: React.FC = () => {
1722
const [previewOpen, setPreviewOpen] = useState(false);
1823
const [generatedContent, setGeneratedContent] = useState('');
24+
const [snackbarOpen, setSnackbarOpen] = useState(false);
25+
const [snackbarMessage, setSnackbarMessage] = useState('');
1926

2027
const handleFormSubmit = (content: string) => {
2128
setGeneratedContent(content);
29+
};
30+
31+
const handleOpenPreview = () => {
2232
setPreviewOpen(true);
2333
};
2434

2535
const handleClosePreview = () => {
2636
setPreviewOpen(false);
2737
};
2838

39+
const handleCopyToClipboard = () => {
40+
navigator.clipboard.writeText(generatedContent).then(() => {
41+
setSnackbarMessage('Copied to clipboard!');
42+
setSnackbarOpen(true);
43+
}, (err) => {
44+
console.error('Could not copy text: ', err);
45+
});
46+
};
47+
48+
const handleDownload = () => {
49+
const element = document.createElement('a');
50+
const file = new Blob([generatedContent], {type: 'text/plain'});
51+
element.href = URL.createObjectURL(file);
52+
element.download = 'generated_context.md';
53+
document.body.appendChild(element);
54+
element.click();
55+
document.body.removeChild(element);
56+
setSnackbarMessage('File downloaded!');
57+
setSnackbarOpen(true);
58+
};
59+
60+
const handleCloseSnackbar = (event?: React.SyntheticEvent | Event, reason?: string) => {
61+
if (reason === 'clickaway') {
62+
return;
63+
}
64+
setSnackbarOpen(false);
65+
};
66+
2967
return (
3068
<ThemeProvider theme={theme}>
3169
<Router basename={BASE_PATH}>
32-
<Container maxWidth="md">
33-
<Paper elevation={3} sx={{ p: 4, mt: 4 }}>
34-
<Box sx={{ mb: 4 }}>
35-
<Typography variant="h4" component="h1" gutterBottom>
70+
<Container className="container" maxWidth="md">
71+
<Paper className="paper" elevation={3}>
72+
<Box className="header">
73+
<Typography className="title" variant="h4" component="h1">
3674
Codebase Context Editor
3775
</Typography>
38-
<Typography variant="body1" paragraph>
39-
This editor helps you create .context.md, .contextdocs.md, and .contextignore files for your project.
40-
</Typography>
41-
<Typography variant="body1" paragraph>
42-
GitHub Repository:{' '}
43-
<MuiLink href="https://github.com/Agentic-Insights/codebase-context-spec" target="_blank" rel="noopener noreferrer">
44-
https://github.com/Agentic-Insights/codebase-context-spec
45-
</MuiLink>
46-
</Typography>
4776
</Box>
77+
<Typography variant="body1" paragraph>
78+
This editor helps you create .context.md, .contextdocs.md, and .contextignore files for your project.
79+
</Typography>
80+
<Typography variant="body1" paragraph>
81+
GitHub Repository:{' '}
82+
<MuiLink href="https://github.com/Agentic-Insights/codebase-context-spec" target="_blank" rel="noopener noreferrer">
83+
https://github.com/Agentic-Insights/codebase-context-spec
84+
</MuiLink>
85+
</Typography>
4886
<NavTabs />
49-
<Routes>
50-
<Route path="/" element={<ContextForm onSubmit={handleFormSubmit} />} />
51-
<Route path="/contextdocs" element={<ContextDocsForm onSubmit={handleFormSubmit} />} />
52-
<Route path="/contextignore" element={<ContextIgnoreForm onSubmit={handleFormSubmit} />} />
53-
</Routes>
87+
<Box className="form-section">
88+
<Routes>
89+
<Route path="/" element={<ContextForm onSubmit={handleFormSubmit} />} />
90+
<Route path="/contextdocs" element={<ContextDocsForm onSubmit={handleFormSubmit} />} />
91+
<Route path="/contextignore" element={<ContextIgnoreForm onSubmit={handleFormSubmit} />} />
92+
</Routes>
93+
</Box>
94+
<Box className="action-buttons">
95+
<Tooltip title="Preview generated content" arrow>
96+
<Button
97+
onClick={handleOpenPreview}
98+
variant="contained"
99+
startIcon={<PreviewIcon />}
100+
disabled={!generatedContent}
101+
>
102+
Preview
103+
</Button>
104+
</Tooltip>
105+
<Tooltip title="Copy to clipboard" arrow>
106+
<Button
107+
onClick={handleCopyToClipboard}
108+
variant="contained"
109+
startIcon={<ContentCopyIcon />}
110+
disabled={!generatedContent}
111+
>
112+
Copy
113+
</Button>
114+
</Tooltip>
115+
<Tooltip title="Download file" arrow>
116+
<Button
117+
onClick={handleDownload}
118+
variant="contained"
119+
startIcon={<DownloadIcon />}
120+
disabled={!generatedContent}
121+
>
122+
Download
123+
</Button>
124+
</Tooltip>
125+
</Box>
54126
</Paper>
55127

56128
<Modal
@@ -59,33 +131,43 @@ const App: React.FC = () => {
59131
aria-labelledby="preview-modal-title"
60132
aria-describedby="preview-modal-description"
61133
>
62-
<Box sx={{
63-
position: 'absolute',
64-
top: '50%',
65-
left: '50%',
66-
transform: 'translate(-50%, -50%)',
67-
width: '80%',
68-
bgcolor: 'background.paper',
69-
boxShadow: 24,
70-
p: 4,
71-
maxHeight: '80vh',
72-
overflow: 'auto',
73-
}}>
74-
<Typography id="preview-modal-title" variant="h6" component="h2" gutterBottom>
75-
Generated File Preview
76-
</Typography>
77-
<Paper sx={{ p: 2, maxHeight: 'calc(80vh - 100px)', overflow: 'auto' }}>
78-
<pre style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>
134+
<Box className="modal-content">
135+
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
136+
<Typography id="preview-modal-title" variant="h6" component="h2">
137+
Preview of generated content
138+
</Typography>
139+
<IconButton onClick={handleClosePreview} size="small">
140+
<CloseIcon />
141+
</IconButton>
142+
</Box>
143+
<Box className="code-preview">
144+
<pre>
79145
{generatedContent}
80146
</pre>
81-
</Paper>
82-
<Box sx={{ mt: 2, display: 'flex', justifyContent: 'flex-end' }}>
83-
<Button onClick={handleClosePreview} variant="contained">
84-
Close
85-
</Button>
86147
</Box>
87148
</Box>
88149
</Modal>
150+
151+
<Snackbar
152+
anchorOrigin={{
153+
vertical: 'bottom',
154+
horizontal: 'center',
155+
}}
156+
open={snackbarOpen}
157+
autoHideDuration={2000}
158+
onClose={handleCloseSnackbar}
159+
message={snackbarMessage}
160+
action={
161+
<IconButton
162+
size="small"
163+
aria-label="close"
164+
color="inherit"
165+
onClick={handleCloseSnackbar}
166+
>
167+
<CloseIcon fontSize="small" />
168+
</IconButton>
169+
}
170+
/>
89171
</Container>
90172
</Router>
91173
</ThemeProvider>

sample.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
module-name: asdfasdf
3+
related-modules:
4+
- name: asdfasdf
5+
path: ./test
6+
version: 1.0.0
7+
description: test
8+
diagrams: []
9+
technologies: []
10+
conventions: []
11+
directives: []
12+
architecture:
13+
style: ''
14+
components: []
15+
data-flow: []
16+
development:
17+
setup-steps: []
18+
build-command: ''
19+
test-command: ''
20+
business-requirements:
21+
key-features: []
22+
target-audience: ''
23+
success-metrics: []
24+
quality-assurance:
25+
testing-frameworks:
26+
- ''
27+
coverage-threshold: '%'
28+
performance-benchmarks: []
29+
deployment:
30+
platform: ''
31+
cicd-pipeline: ''
32+
staging-environment: ''
33+
production-environment: ''
34+
---
35+
36+
test

0 commit comments

Comments
 (0)